Java开发从入门到精通(八):Java的面向对象编程OOP:封装、继承、多态

(一)Java的封装

1.1 什么是封装

  • 就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去
  • 要处理的数据
  • 处理数据的方法
  • 写到一个类里就是封装 如下

在这里插入图片描述

1.1.1 封装的设计规范

  • 合理隐藏
  • 合理暴露
  • private
public class Student {
    private String name; 
    double chinese; 
    double math;
    
    private void printTotalScore() { 
        System.out.println(name + "的总成绩是:" + (chinese + math));
    }

    public void printAverageScore() {
        System.out.println(name + "的平均成绩是:" + (chinese + math) / 2.0);
    }
}

怎么达到合理隐藏 合理暴露呢
控制输入
控制输出

为了防止别人随意传值,使用私有化变量,然后让用户通过公有方法访问给私有变量赋值

public class Student {

    private String name; // 私有变量 不允许访问
    private double score;
    private double math;

    public void  setScore(String name,double score,double math){
        if ((score >= 0 && score <= 100) && (math >=0 && math<=100)){
            this.name = name;
            this.score = score;
            this.math = math;
        } else {
            System.out.println("数据非法");
        }

    }

    public double getScore(){
        return score;
    }

    private void printTotalScore() { // 私有方法 不允许访问
        System.out.println(name + "的总成绩是:" + (chinese + math));
    }

    public void printAverageScore() {
        System.out.println(name + "的平均成绩是:" + (chinese + math) / 2.0);
    }
}
public class Test {
    public static void main(String[] args) {
        // 目标:掌握封装的设计规范:合理隐藏、合理暴露。
        Student s1 = new Student();
        s1.setScore("liyang",55,66);
        System.out.println(s1.getScore());
    }
}

1.1.2 代码层面如何控对象的成员公开或隐藏?

  • 公开成员,可以使用public(公开)进行修饰。
  • 隐藏成员,使用private(私有,隐藏)进行修饰。

1.2 JavaBean(实体类)

什么是实体类?

  • 就是一种特殊形式的类。
    在这里插入图片描述

1.2.1创建实体类

  • 1.先创建两个私有变量
public class Student {
    private String name;
    private double score;
}

2.选中变量右键选择generate,可以创建有参构造器,set方法,get方法
在这里插入图片描述
在这里插入图片描述

  • 3.无参构造方法选择selec none

在这里插入图片描述

public class Student {
	//1、必须私有成员变量,并为每个成员变量都提供getset方法
    private String name;
    private double score;
    //2、必须为类提供一个公开的无参数构造器
    public Student() {
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public double getScore() {
        return score;
    }
}

public class Test {
    public static void main(String[] args) {
        //目标:掌握实体类的书写要求、特点、应用场景
        Student s1 = new Student();
        s1.setName("播妞");
        s1.setScore(99);
        System.out.println(s1.getName());
        System.out.println(s1.getScore());
    }
}

1.2.2 实体类有啥应用场景?

  • 实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离

在这里插入图片描述
操作类处理数据

public class StudentOperator {
    private Student student;

    public StudentOperator(Student student) {
        this.student = student;
    }

    public void printPass() {
        if (student.getScore() >= 60) {
            System.out.println(student.getName() + "学生成绩及格");
        } else {
            System.out.println(student.getName() + "学生成绩不及格");
        }
    }
}

实体类保存数据

```java
public class Test {
    public static void main(String[] args) {
        //目标:掌握实体类的书写要求、特点、应用场景
        Student s1 = new Student();
        s1.setName("播妞");
        s1.setScore(99);
        System.out.println(s1.getName());
        System.out.println(s1.getScore());
        
        StudentOperator operator =new StudentOperator(s1);
        operator.printPass();
    }
}

1.2.3 实体类总结

  • 什么是实体类?有啥特点?
    • 成员变量必须私有,且要为他们提供get、set方法;必须有无参数构造器
    • 仅仅只是一个用来保存数据的java类,可以用它创建对象,保存某个事物的数据。
  • 实体类有啥应用场景?
    • 实体类对应的是软件开发里现在比较流行的开发方式,数据和数据的业务处理相分离

1.3 继承

1.3.1 继承的语法格式

  • Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。

在这里插入图片描述
继承的特点

  • 子类能继承父类的非私有成员(成员变量、成员方法)

继承后对象的创建

  • 子类的对象是由子类、父类共同完成的。

先写一个类A

public class A{
	//公开成员
	public int i;
	public void print1(){
		System.out.println("===print1===");
	}
	// 私有成员
	private int j;
	private void print2(){
	System.out.println("===print2===");
	}
}

再写一个类B继承A

// 子类
public class B extends A{
	private int k;  
	//子类是可以继承父类的非私有成员
	public void print3(){
		System.out.println(i);  //直接访问A的公开成员和方法
		print1();
		
		// System.out.println(j);
		// print2();

那如果此时我们创建一个对象b 这个b可以继承那些东西?
此时的b是由A和B两个设计图共同创建的表,可以使用A和B的所有公开成员变量和方法

public class Test {
	public static void main(string[] args){
			// 目标:认识继承、掌握继承的特点。
			B b = new B();
			System.out.println(b.i);
			// System.out.println(b.j);
			// System.out.println(b.k);
			
			b.print1();
			//b.print2();
			b.print3();

在这里插入图片描述

1.3.2 继承的执行原理

当创建一个B对象时,具体的过程如下:

  • 类加载:JVM 会将A类和B类的字节码加载到方法区中。方法区存储了类的元数据,包括类的定义、常量、静态变量和方法。
  • 实例化B对象:在堆内存中创建一个B对象的实例。堆内存用于存储对象的实例数据。
  • 继承属性:B对象会继承A类的公开成员变量i。这意味着B对象具有A类的公开属性,可以直接访问和使用。
  • 方法继承:B类继承了A类的公开方法print1。因此,B对象可以调用print1方法,就像它是自己的方法一样。
  • 私有成员限制:由于j是A类的私有成员,根据 Java 的封装原则,子类(B)无法直接访问父类的私有成员。尝试访问b.j会导致编译错误。
  • 子类特有属性:B类定义了自己的私有成员变量k,它是B类特有的,与父类A无关。
  • 在方法区中,存储了类的信息,包括类的定义、方法和变量。方法区中的数据在程序运行期间是共享的。
  • 栈内存用于方法调用和局部变量的存储。当调用B类的方法时,相关的方法参数和局部变量会被压入栈中。
  • 堆内存用于存储对象实例。每个对象都有自己的内存空间,包括继承自父类的成员和子类自己定义的成员。

在这里插入图片描述

1、什么是继承?继承后有啥特点 ?

  • 继承就是用extends关键字,让一个类和另一个类建立起一种父子关系。.
  • 子类可以继承父类非私有的成员。

2、带继承关系的类,Java会怎么创建它的对象?对象创建出来后,可以直接访问哪些成员?

  • 带继承关系的类,java会用类和其父类,这多张设计图来一起创建类的对象。
  • 对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员。

1.3.3 使用继承有啥好处?

  • 减少重复代码的编写。

继承的案列讲解
这两个类存在大量重复代码 怎么能简化一下,省去编写这么的重复代码的力气呢
在这里插入图片描述
那就是采用继承,让两个类继承重复的代码,然后直接调用
在这里插入图片描述
先新建一个People类

public class People {
	private String name;
	public string getName(){
		return name;
	}
	public void setName(string name){
		this.name = name;
	}

在创建一个教师类继承People类

public class Teacher extends People{
	private string skill;
	public string getSkill(){
		return skill;
	}
	public void setSkill(string skill){
		this.skill = skill;
	}

在创建一个咨询师类继承People类

public class ConsuIktant extends People{
	private int number;
	public int getNumber(){
		return number;
	}
	public void setNumber(int number){
		this.number = number;
	}

在写一个Test类 使用main方法是作为Java 程序的入口点 调用其他方法等,从而控制程序的执行顺序和逻辑。

public class Test {
	public static void main(string[]args){
	// 目标:搞洁楚继承的好处。
	Teacher t= new Teacher();
	t.setName(“播仔");
	t.setSkill("Java、Spring");
	System.out.println(t.getName());
	System.out.println(t.getskill());
	t.printInfo();
	}
}

1.3.4 继承的注意事项

1.3.4.1 权限修饰符
  • 什么是权限修饰符?
  • 就是是用来限制类中的成员(成员变量、成员方法、构造器、代码块…)能够被访问的范围。
  • 权限修饰符有几种?各自的作用是什么?
    在这里插入图片描述
    编写一个修饰符的测试类
public class Fu {
	// 1、私有:只能在本类中访问
	private void privateMethod(){
		System.out.println("==private==");
	}
	// 2、缺省:本类,同一个包下的类
	void method(){
		System.out.println("==缺省==");
	}
	// 3、protected:本类,同一个包下的类,任意包下的子
	protected void protectedMethod(){
		System.out.println("==protected==");
	}
	// 4、public: 本类,同一个包下的类,任意包下的子类,
	public void publicMethod(){
		System.out.println("==public==");
	}
	// 5、本类中测试调用不同修饰符的方法
	public void test(){
		privateMethod();
		method();
		protectedMethod();
		publicMethod();
	}

在同一个包类下的其他类调用不同修饰符的方法

public class Demo {
	public static void main(string[]args){// 目标:掌握不同权限修饰符的作用。
	Fu f = new Fu();
	// f.privateMethod();  不允许调用私有方法
	f.method();
	f.protectedMethod();
	f.publicMethod();
	}
}

在任意包下的子类里调用不同修饰符的方法

public class Zi extends Fu {
	public void test(){
		// privateMethod();// 报错
		// method();// 报错
		protectedMethod();
		publicMethod();
	}
}

在任意包下的任意类里调用不同修饰符的方法

public class Demo2{
	public static void main(string[] args){
		Fu f = new Fu();
		// f.privateMethod();// 报错
		// f.method();// 报错
		// f.protecedMethod();// 报错
		f.publicMethod();  //完全暴露
	}
}
1.3.4.2 单继承、0bject类
  • Java是单继承的,Java中的类不支持多继承,但是支持多层继承
    在这里插入图片描述
public class Test {
	public static void main(String[]args){
	//目标:掌握继承的两个注意事项事项。
	// 1、Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但是支持多层继承。
	//2、0bject类是Java中所有类的祖宗。
	}
class A{}
class B extends A{}
class C extends BA{} // 报错
class D extends B{}  //D 继承B B继承A 这就是多层继承
}

为何Java中的类不支持多继承
在这里插入图片描述
请看如下反证法:
在这里插入图片描述
0bject类
object类是java所有类的祖宗类。我们写的任何一个类,其实都是object的子类或子孙类。

class A{}
//实际默认继承了0bject类
class A{}//extends 0bject{}
public class Test {
	public static void main(String[]args){
	//目标:掌握继承的两个注意事项事项。
	// 1、Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但是支持多层继承。
	//2、0bject类是Java中所有类的祖宗。
	A a= new A();
	a.如下图会自动显示多个方法 这些方法都是0bject类的
	}

在这里插入图片描述

  • B类就是0bject类的孙子类 B继承了A 继承了0bject类 B也就继承了0bject类
class A{}
class B extends A{}  
B b = new B();
b.如下图会自动显示多个方法 这些方法都是0bject类的

在这里插入图片描述

  • object类是java所有类的祖宗类。我们写的任何一个类,其实都是object的子类或子孙类。

在这里插入图片描述

1.3.4.3 方法重写
  • 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
  • 注意:重写后,方法的访问,Java会遵循就近原则

在这里插入图片描述

方法重写的其它注意事项

  • 重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好,
  • 子类重写父类方法时 访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)
  • 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
  • 私有方法、静态方法不能被重写,如果重写会报错的。

在这里插入图片描述
私有方法、静态方法不能被重写,如果重写会报错的。
在这里插入图片描述
在这里插入图片描述

方法重写在开发中的常见应用场景
子类重写0bject类的toString()方法,以便返回对象的内容

public class student extends 0bject{
	private String name;
	private int age;
	public student(){
	}
	public Student(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public int getAge(){
		return age;
	}
	public void setAge(int age){
		this.age = age;
	}

输出对象时默认调用的就是tostring 但是object类自带的toString方法返回的东西是内存地址,不是我们想要的

public class Test {
	public static void main(string[]args){
	// 目标:认识方法重写,掌握方法重写的常见应用场景。
		Bb=new B();
		b.print1();
		b.print2( a:2,b:3);
		System.out.println("-------------------------")
		Students =new Student( name:"播妞",age: 19);
		//System.out.println(s.tostring());  
		System.out.println(s);  //输出对象时默认调用的就是tostring
	@Override
	public string tostring(){
		return "Student{name=" + name + ",age=" + age + "}";
	}

完整代码

public class student extends 0bject{
	private String name;
	private int age;
	public student(){
	}
	public Student(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public int getAge(){
		return age;
	}
	public void setAge(int age){
		this.age = age;
	}
	@Override
	public string tostring(){
		return "Student{name=" + name + ",age=" + age + "}";
	}
Student{name=播妞,age=19}

右键还可以自动生成重写代码 选择tostring

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.3.4.4 子类中访问其他成员的特点

1、在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的

  • 先子类局部范围找。
  • 然后子类成员范围找。
  • 然后父类成员范围找,如果父类范围还没有找到则报错

2、如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法

  • 访问重名的成员变量name 会就近选择方法内部的name
  • 访问子类的变量就需要使用this.子类变量 访问父类 super.父类变量 就近原则

在这里插入图片描述

  • 访问重名的成员方法
  • 访问父类方法使用super.父类方法() 访问子类方法使用子类方法() 就近原则
    在这里插入图片描述
1.3.4.5 子类构造器的特点
  • 子类的全部构造器,都会先调用父类的构造器,再执行自己
    在这里插入图片描述
class F{
	public F(){
		System.out.println("===父类F的 无参数构造器 执行了===");
	}
class Z extends F{
	public 2(){
		// super();// 默认存在的
		System.out.println("===子类Z的 无参数构造器 执行了===");
	}
	public Z(String name){
		//super();// 默认存在的
		System.out.println("===子类Z的 有参数构造器 执行了===");
	}
public class Test{
	public static void main(String[]args){// 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景。
		Z z= new Z();
		Z z2= new Z( name:"播妞");
	}
}

父类只有有参构造器了 ,子类的super会报错,要不想报错就让super调用有参构造器 super( name:“播妞”,age: 17);

class F{
	//public F(){
		//System.out.println("===父类F的 无参数构造器 执行了===");
	//}
	public F(String name,int age){
		System.out.println("===父类F的 无参数构造器 执行了===");
	}
	
class Z extends F{
	public 2(){
		// super();// 默认存在的
		super( name:"播妞",age: 17);
		System.out.println("===子类Z的 无参数构造器 执行了===");
	}
	public Z(String name){
		//super();// 默认存在的
		super( name:"播妞",age: 17);
		System.out.println("===子类Z的 有参数构造器 执行了===");
	}
public class Test{
	public static void main(String[]args){// 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景。
		Z z= new Z();
		Z z2= new Z( name:"播妞");
	}
}

子类构造器是如何实现调用父类构造器的

  • 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器
  • 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(…),指定去调用父类的有参数构造器

目标:搞清楚子类构造器为什么要调用父类构造器,有啥应用场景上

public class Test2{
	public static void main(String[]args){
	//1 目标:于类调用父类构造器的常见应用场景。
	Teacher t= new Teacher("李四",36,"Java");
	System.out.println(t.getName());
	System.out.println(t.getAge());
	System.out.println(t.getski11());
class People{
	private string name;
	private int age;
	public People(){
	}
	public People(string name, int age){
		this.name = name;
		this.age = age;
	}
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
class Teacher extends People{
	private string skill;
	public Teacher(){
	}
	public Teacher(string name,int age, string skill){
		super(name,age);
		this.skill =skill;
	}
	public String getSkill() {
        return skill;
    }
    public void setSkill(String skill) {
        this.skill = skill;
    }
}

子类构造器调用父类构造器的执行原理

  • 子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化赋值
  • 再回来把对象里包含子类这部分的数据也进行初始化赋值。
public Teacher(string name,int age, string skill){
		super(name,age);
		this.skill =skill;
	}

在这里插入图片描述

this(…)调用兄弟构造器

  • 任意类的构造器中,是可以通过this(…)去调用该类的其他构造器的
public class Test {
    public static void main(String[] args) {
    	
        //! 需求:如果学生没有填写学校,那么学校默认就是黑马程序员
        Student s2 = new Student( name:"张三",age: 28);
        System.out.println(s2.getName());
        System.out.println(s2.getAge());
        System.out.println(s2.getSchoolName());

    }
    
class Student{
    private String name;
    private int age;
    private String schoolName;

    public Student() {
    
    }
    public Student(string name, int age){
       	//this.name = name;
       	//this.age = age;
        //this.schoolName = "黑马程序员";
    	this(name,age,schoolName:"黑马程序员");  //任意类的构造器中,是可以通过this(...)去调用该类的其他构造器的
    }
    public Student(String name, int age, String schoolName) {
        this.name = name;
        this.age = age;   //this调用的就是这个类
        this.schoolName = schoolName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSchoolName() {
        return schoolName;
    }
    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}

this(…)和super(…)使用时的注意事项:

  • this(…)、super(…)都只能放在构造器的第一行,因此,有了this(…)就不能写super(…)了,反之亦然。

1.4 多态

1.4.1 什么是多态?

  • 多态是在继承/实现情况下的一种现象,表现为:对象多态行为多态

1.4.2 多态的具体代码体现

public class People {
    public void run(){
        System.out.println("人跑得很快");
    }
}
public class Teacher extends People{
    @Override
    public void run() {
        System.out.println("老师跑得很快");
    }
}
public class Student extends People{
    @Override
    public void run() {
        System.out.println("学生跑的很快");
    }
}

识别技巧:编译看左边,运行看右边 就是编译的时候编译people 运行的时候按照student类运行 在student类里寻找

public class Test {
    public static void main(String[] args) {
	    // 目标:认识多态:对象多态,行为多态。
	    // 1、对象多态
        People P1 = new Teacher();
        P1.run();//识别技巧:编译看左边,运行看右边
        People P2 = new Student();
        P2.run();


    }
}

在这里插入图片描述

多态的前提

  • 继承/实现 关系 存在父类引用子类对象 存在方法重写

多态的一个注意事项

  • 多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
  • 对于变量,编译看左边,运行看左边 就是看people中有什么就是执行什么
public class Test {
    public static void main(String[] args) {
	    // 目标:认识多态:对象多态,行为多态。
	    // 1、对象多态
        People P1 = new Teacher();
        P1.run(); // 识别技巧:编译看左边,运行看右边
        System.out.println(P1.name); //注意:对于变量,编译看左边,运行看左边
        People P2 = new Student();
        P2.run();


    }
}

1.4.3 使用多态的好处

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护
  • =号右边随时可以把Teacher换成Student 这就是解耦合
  • 如果右边写死不能随时更换,那就是紧耦合

在这里插入图片描述
在这里插入图片描述

  • 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利
public class Test {
	public static void main(string[] args){
		// 目标:理解多态的好处
		// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
		People p1=new student();
		p1.run();
		
		// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
		Student s =new Student();
		go(s);
		Teacher t = new Teacher();
		go(t);
		public static void go(People p){
		}

多态下会产生的一个问题,怎么解决?

  • 多态下不能使用子类的独有功能。
public class Teacher extends People{
    @Override
    public void run() {
        System.out.println("老师跑得很快");
    }
    public void test(){
		System.out.println("老师需要教知识~~~");
	}
}
public class Student extends People{
    @Override
    public void run() {
        System.out.println("学生跑的很快");
    }
    public void test(){
		System.out.println("学生需要考试~~~");
	}
}
public class Test {
	public static void main(string[] args){
		// 目标:理解多态的好处
		// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
		People p1=new student();
		p1.run();
		p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
		
		// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
		Student s =new Student();
		go(s);
		Teacher t = new Teacher();
		go(t);
		public static void go(People p){
		}

1.4.4 类型转换

  • 自动类型转换:父类 变量名=new 子类();
  • 强制类型转换:子类 变量名=(子类)父类变量

强制类型转换的一个注意事项
存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。

public class Test {
	public static void main(string[] args){
		// 目标:理解多态的好处
		// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
		People p1=new student();
		p1.run();
		p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
		
		// 强制类型转换
		Student s1=(student)p1;
		s1.test();
		//! 强制类型转换可能存在的问题:编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
		Teacher t1 = (Teacher) p1; // 运行时出现了:ClassCastException

		// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
		Student s =new Student();
		go(s);
		Teacher t = new Teacher();
		go(t);
		
		public static void go(People p){
		}

强转前,Java建议:

  • 使用instanceof关键字,判断当前对象的真实类型,再进行强转。
p instanceof Student
public class Test {
	public static void main(string[] args){
		// 目标:理解多态的好处
		// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
		People p1=new student();
		p1.run();
		p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
		
		// 强制类型转换
		Student s1=(student)p1;
		s1.test();
		//! 强制类型转换可能存在的问题:编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
		Teacher t1 = (Teacher) p1; // 运行时出现了:ClassCastException
		if(p1 instanceof Student){
			Student s2 = (student) p1;
			s2.test();
		}else {
			Teacher t2 = (Teacher) p1;
			t2.teach();
		}
		System.out.println("---------------------")
		// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
		Student s = new Student();
		go(s);
		Teachert = new Teacher();
		go(t);

		public static void go(People p){
			p.run();
			if(p instanceof student){
				Students=(Student)p;
				s.test();
			}else if(p instanceof Teacher){
				Teachert=(Teacher)p;
				t.teach();
			}
		}
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HACKNOE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值