java-面向对象三大特性:封装、继承、多态

hushuo
发布于 2021-1-8 11:06
浏览
0收藏

封装
属性的修饰符
首先有4个访问修饰符:private;protected;public以及默认也就是前面什么都不加。
在企业中,建议一般将属性修饰符定义为private,为什么呢,因为是私有的,只有当前类可以访问。 这样就可以保证私密性,如果用public修饰那么谁都可以进入当前类,那不就可以随便看你的属性,这样多么不安全。以及在使用构造函数new对象时,如果随意给属性赋值那么会产生很严重的问题。
private 修饰属性后,通过getter以及setter来让创建的对象进行属性的取值和赋值
举一个栗子

/**
现在有一个类来描述汽车,有属性:价格、品牌。
*/
/**
 * 汽车类
 * 
 * @author Mould
 *
 */
public class Car {
  private int price ; //价格
 /**
  * 品牌
  */
 private  String brand;
 
 
 public String getBrand() {//输出属性值,一般情况下
  if(band == Null){
   band = "" ; //这样就避免了输出null,因为非程序员不理解null是啥,我们就用空字符串输出
   }else{
  return brand;
  }
  
 }
 public void setBrand(String brand) {
  if(band == "mini"){//这个对传递的品牌进行判断。这个就避免了用户随意传值。
   band = "宝马" ;
   }else{
  this.brand = brand;
  }
 }
//再将main方法写在另外一个同包的java文件中,不建议将main方法写在类中
//这样就可以给对象的属性通过setBrand()给品牌赋值,通过setBrand()取出品牌值,这里只写了品牌这个属性,其他属性是一样
//的,就是在方法名中Brand改为你想赋值以及取值的属性名
public class CarDemo {

 public static void main(String[] args) {
  Car car = new Car() ;
  car.setBrand("mini");
  String b = car.getBrand() ;
  System.out.println("品牌为:" + b) ;

 }

}


封装的作用

  • 对属性的访问进行控制
  • 一个类对外隐藏实现的细节
    最上面的栗子是对属性进行讲解,也就是第一个作用
    第二个作用主要是作用于方法。
    再举个栗子
    我们启动汽车,无论是一键启动,还是用钥匙拧开,汽车都会启动,其实汽车启动的过程可以分解为喷油–活塞花点火–启动引擎。那么我们实际上都没有进行这些操作流程,那么就是系统自己将启动的过程封装成了一个方法叫启动,一旦用户点了启动,那么系统自己偷偷后台运行这些流程,我们用户无法调用喷油这个方法,点火这个方法以及启动这个方法。就是将这些方法隐藏起来了。
    上代码
    public class Car {
     /**
      * 这里面就不写汽车属性了,主要写汽车启动的过程
      */
     public void start() {//启动方法
      //因为该方法是public修饰的所以任何地方都可以访问到
      oil();
      fireUp();
      startEngine();
     }
     
     /**
      * 喷油,修饰为private那么只能在本类中被调用
      */
     private void oil() {
      System.out.println("汽车开始喷油");
     }
     /**
      * 点火,修饰为private那么只能在本类中被调用
      */
     private void fireUp() {
      System.out.println("汽车开始点火");
     }
     /**
      * 启动发动机,修饰为private那么只能在本类中被调用
      */
     private void startEngine() {
      System.out.println("汽车发动机启动");
     }
    }​

    再写一个.java文件进行创建对象调用启动方法
public class CarDemo {

 public static void main(String[] args) {
  // 构造汽车类的对象
  Car car1 = new Car() ;
  car1.start();//汽车启动
  //car1.oil(); //这个会报错,因为private修饰不能再其他类中访问到。

 }

}


继承
java只有单继承,也就是一个子类只能继承一个父类,换言之,只有一个爸爸。但是可以你继承你爸爸的,你爸爸继承你爷爷的,你爷爷继承你太爷爷的,一直这样继承下去,那么你就暗地里继承了你太爷爷的,你爷爷的。这样说人话,好理解,好记忆。
子类自动有了父类的属性和方法。这样就减少代码的冗余,便于维护和扩展。子类可以写自己的属性和方法。
继承使用extends关键字

举个栗子:如何继承减少代码冗余度。

java-面向对象三大特性:封装、继承、多态-鸿蒙开发者社区
上代码

//动物类
public class Animal {
 /**
  * 公有属性:年龄
  */
 protected String brand ;
 protected int age ;
 protected String sex ;
 
 protected void eat() {
  System.out.print("调用动物类的吃方法");
 }
 
 protected void dirnk() {
  System.out.print("调用动物类的喝方法");
 }
}

 

//同包文件下创建一个Dog类继承Animal
public class Dog extends Animal{
 protected String furColor ; //狗独有的属性:毛色,动物类里面没有就要单独写
 protected String size ; //大小
}

 

//同包下创建YanZi类
public class YanZi extends Animal {
//这里面啥都不用写,因为继承动物类就行了,这不用写代码,不香吗。
}


有啥不能继承的

  • 父类的构造函数能继承吗,(答案是不能,因为构造方法和类名同名,父类名和子类名怎么相同呢)
  • 父类的私有的属性和方法,他们能继承吗,(答案是不能,因为构造方法和类名同名,父类名和子类名怎么相同呢)
    访问修饰符
    java-面向对象三大特性:封装、继承、多态-鸿蒙开发者社区

方法的重写
重写(overload)是子类继承父类时,父类写了某个方法,但是子类想用时,发现部分不是自己想要的或者是完全都不是自己想要的,那么就写一个和父类这个方法相同的方法名。那么在子类中调用该方法自动调用子类重写的方法。
举个栗子

//这里就用上面的动物来写吧,只是简单的栗子,证明上面的栗子
//修改Dog.java文件
public class Dog extends Animal{
 protected String furColor ; //狗独有的属性:毛色,动物类里面没有就要单独写
 protected String size ; //大小
 
 @Override//解释器作用,表示下面的方法是重写
 public void eat() {
  System.out.println("狗喜欢吃的到处都是");
 }
 
}

 

//同包下创建Demo.java
public class Demo {

 public static void main(String[] args) {
  Dog dog = new Dog() ;
  dog.eat();

 }

}
//运行这个程序


看结果
java-面向对象三大特性:封装、继承、多态-鸿蒙开发者社区

可以使用@Override注解定义在方法上,用来检查该方法是否构成方法的重写。
栗子就在上面的代码那里

super关键字的用法

  • super就是代指父类的对象
  • super()就是调用父类的无参构造方法,和this()很像。
  • super.属性和super.方法名()调用父类的属性和方法。这个一般使用在子类重写了父类方法,因为重写了父类方法,那么父类的该方法就不能被调用了
  • super()必须写在方法中第一行,父类嘛,答谢当然要先写它。


看个栗子,子类重写了父类的方法,采用super.方法名()调用父类的方法,

public class Animal {
 /**
  * 公有属性:年龄
  */
 protected String brand ;
 protected int age ;
 protected String sex ;
 
 protected void eat() {
  System.out.print("调用动物类的吃方法");
 }
 
 protected void dirnk() {
  System.out.print("调用动物类的喝方法");
 }
}

 

public class Dog extends Animal{
 protected String furColor ; //狗独有的属性:毛色,动物类里面没有就要单独写
 protected String size ; //大小
 
 @Override//解释器作用,表示下面的方法是重写
 public void eat() {
  super.eat(); //调用父类的eat()方法
  System.out.println("狗喜欢吃的到处都是");
  //super.eat(); //这样会报错,super()必须放在第一行
 }
 
}

 

public class Demo {

 public static void main(String[] args) {
  Dog dog = new Dog() ;
  
  dog.eat();
  
 }

}



java-面向对象三大特性:封装、继承、多态-鸿蒙开发者社区

举个栗子,super调用父类的构造方法

//父类
public class Animal {
 /**
  * 公有属性:年龄
  */
 protected String brand ;
 protected int age ;
 protected String sex ;
 
 
 public Animal(int age , String sex) {
  this.age = age ;
  this.sex = sex ;
 }
 
 public Animal(String brand ,int age , String sex) {
  this(age,sex); //直接采用this(参数)来调用其他的构造方法
  this.brand = brand;
  //this(age,sex); //直接采用this(参数)来调用其他的构造方法
 }
 protected void eat() {
  System.out.println("调用动物类的吃方法");
 }
 
 protected void dirnk() {
  System.out.println("调用动物类的喝方法");
 }
}

 

//子类-Dog
public class Dog extends Animal{
 protected String furColor ; //狗独有的属性:毛色,动物类里面没有就要单独写
 protected String size ; //大小
 
 public Dog(String brand ,int age , String sex , String furColor , String size ) {//因为父类里面包含-有参构造方法,那么子类必须定义个构造函数,
  //因为默认情况系统写个无参的构造函数自己调用了,但是你在类里面写了有参构造方法,那么就会调用你写的有参的构造函数
  super(brand , age , sex);//super()必须放在第一行,调用父类的有三个参数的构造方法
  this.furColor = furColor ; //这个是子类的构造函数传值
  this.size = size ; //这个是子类的构造函数传值
  
 }
 @Override//解释器作用,表示下面的方法是重写
 public void eat() {
  super.eat(); //调用父类的eat()方法
  System.out.println("狗喜欢吃的到处都是");
  //super.eat(); //这样会报错,super()必须放在第一行
 }
 
}

 

//子类-燕子
public class YanZi extends Animal {

 public YanZi(int age, String sex) {
  super(age, sex);
  // TODO Auto-generated constructor stub
 }

}

 

public class Demo {

 public static void main(String[] args) {
  Dog dog = new Dog("哈士奇" , 3 , "男" , "黑白色" , "中性犬") ;//子类的构造方法
  
  dog.eat();//子类的eat()方法
  
 }

}


多态
使用父类的引用去指向子类的对象。
此时只能调用父类里面有的属性和方法。如果子类中有重写父类的方法,那么会调用子类的重写后的方法。
Father father = new Son();
//等号左边,用父类的变量
//等号右边,new 子类的对象
然后father这个对象名只能调用父类里面的方法。
如果子类里面有重写父类里面的方法,那么father.那个方法名(),实际上调用的是子类里面重写的方法。调用其他没有重写的方法,就调用父类里面的方法。

使用场景:

方法参数的多态
方法返回值的多态
现在父类是动物类,有方法:吃和睡。
一个子类:狗,有方法:吃,睡,狗叫,摇尾巴。
另一个子类:猫,有方法:吃,喝,猫叫。
有个主人类:有方法喂食物。
上代码。

public class Animal {
 public void shock() {
  System.out.println("动物在叫");
 }
 
 public void eat() {
  System.out.println("动物在吃");
 }
}

 

public class Dog extends Animal{
 @Override
 public void shock() {
  System.out.println("狗在汪汪叫");
 }
 @Override
 public void eat() {
  System.out.println("狗在吃");
 }
 
 public void sleep() {
  System.out.println("狗在睡");
 }
}

 

public class Cat extends Animal{
 @Override
 public void shock() {
  System.out.println("猫在叫");
 }
 @Override
 public void eat() {
  System.out.println("猫在吃");
 }
}

 

public class Master {
 public void feed( Animal a) {
  a.eat();
 }
 public Animal play() {
  //返回值是一个类
  //这也是一个多态
  return new Cat() ;
 }
}

 

public class Demo {
 public static void main(String [] args) {
  /**
   * 父类的引用指向子类的对象,只能调用父类里面有的方法,
   * 如果该方法被子类重写那么实际调用子类的方法
   */ 
  Animal a  = new Dog() ;
  a.eat();
  a.shock();
  Dog dog = new Dog() ;
  Master m = new Master() ;
  m.feed(a);//参数为父类类型,但是开辟的是子类的对象,就调用子类重写的方法。
  m.feed(dog);//这里是将创建子类对象,传到父类的类型,这样就实现了多态的可扩展性。
 }



收藏
回复
举报
回复
    相关推荐