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

封装

属性的修饰符
首先有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关键字

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

在这里插入图片描述
上代码

//动物类
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 {
    
    
//这里面啥都不用写,因为继承动物类就行了,这不用写代码,不香吗。
}

有啥不能继承的

  • 父类的构造函数能继承吗,(答案是不能,因为构造方法和类名同名,父类名和子类名怎么相同呢)
  • 父类的私有的属性和方法,他们能继承吗,(答案是不能,因为构造方法和类名同名,父类名和子类名怎么相同呢)

访问修饰符

在这里插入图片描述

方法的重写

重写(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();

	}

}
//运行这个程序

看结果
在这里插入图片描述

可以使用@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();
		
	}

}

在这里插入图片描述

举个栗子,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);//这里是将创建子类对象,传到父类的类型,这样就实现了多态的可扩展性。
	}
}

instanceof关键字

用法
对象 instanceof 类名
例如 有个类Father ,Son,Daughter.并且有它们的对象fahter,son,daughter.如果想判断对象是不是某个类的对象。
意义:
判断某个对象是不是某个类创建的对象。

猜你喜欢

转载自blog.csdn.net/toomemetoo/article/details/112286085