JAVA11_08学习总结(继承!多态引入)

发布于:2022-11-08 ⋅ 阅读:(836) ⋅ 点赞:(0)

今日内容

1.继承(★)

1.1继承注意事项

注意事项
    1)子类不能直接继承父类的私有化属性,可以间接访问
    2)父类的构造方法是不能被继承的,只能间接访问---通过super

1.2继承中成员变量访问问题

成员变量访问问题
    1)在继承中,子类的成员变量名和父类的成员变量名不一致,分别访问即可
    2)如果子类的成员变量名和父类的成员变量名一致
        就近原则机制
            ---先在子类的局部位置(成员方法)中找,有则直接用
            ---如果子类的局部位置没有,在子类的成员位置找,有则直接使用
            ---如果还是没有,就在父类的成员位置中找,有则直接使用
            ---还是没有就往父类的父类成员位置中找,有则直接使用
                ---如此反复,若到顶部位置还是没有,则报错!
public class Fu {
    //父类成员位置的num变量
    int num = 10 ;
}
​
​
​
public class Zi extends Fu {
    //子类成员变量位置的num变量
    int num = 20 ;
    public void show(){
        //子类局部位置的num变量
        int num = 30 ;
        //此时,show方法被调用,输出哪个num?
        System.out.println(num);
    }
}
​
​
​
public class extendsTest {
    public static void main(String[] args) {
        Zi z = new Zi() ;
        //会输出哪个num?
        z.show();//30
    }
}

1.3this和super区别

this
    代表当前类对象的地址引用
        this()---指向本类的无参构造方法
        this(XX)---只想本类的有参构造方法
super
    代表当前子类父类的空间标识
        ---父类对象空间地址值引用
            super()---指向父类的无参构造方法
            super()---指向父类的有参构造方法
public class Fu {
    int num = 10 ;
}
​
​
​
public class Zi extends Fu {
    int num = 20 ;
    public void show(){
        int num = 30 ;
        //就近原则
        System.out.println(num);//30
        //this---代表当前类对象的地址引用
        System.out.println(this.num);//20
        //super---代表父类对象空间地址值的引用
        System.out.println(super.num);//10
    }
}
​
​
​
public class extendsTest1 {
    public static void main(String[] args) {
        Zi z = new Zi() ;
        z.show();
    }
}

1.4构造方法与继承

构造方法与继承
    构造方法的目的
        类的成员进行数据初始化
    子类不能继承父类的构造方法,但是可以通过super来间接访问---为什么?是不是多此一举
        子类的所有构造方法,都默认访问父类的无参构造方法!
            ---因为在子类初始化时可能用到父类的数据,所以需要父类先初始化
                ---所有子类构造方法第一句是super();可省略但不是没有!

1.4.1面试题

继承关系中, 父类的中如果没有无参构造方法(存在有参构造方法),子类会出现什么情况?如何解决呢?

分析
    父类定义了的有参的构造方法,所以系统不会默认存在无参的构造方法
    子类会怎么样?
        子类会全部报错,子类的所有构造方法都默认指向父类无参的构造方法!
    该如何解决
        1)给父类添加无参构造方法
        2)让所有子类的所有构造方法都指向父类有参的构造方法
        3)子类的所有构造方法中只要有一个可以让父类初始化即可
            执行本类的创建面向对象的无参构造方法时
                --->先访问子类的有参构造方法---this(xx)
                    --->再让有参构造方法---super(xx)
                        --->访问父类的有参构造方法
    子类的无参构造方法---访问父类的无参构造方法
    子类的有参构造方法---访问父类的有参构造方法
//父类没有无参的构造方法public Fu(){}
public class Fu {
    //父类有参构造方法,接收数据完成父类初始化!
    public Fu(String name){
        System.out.println("猜猜我是谁?    我是:"+name);
    }
}
​
​
​
public class Zi extends Fu {
    //子类的无参构造方法,通过this特性访问子类的有参构造方法
    public Zi(){
        this("钟离") ;
    }
    //子类的有参构造方法,通过super特性访问父类的有参构造方法,完成父类初始化!
    public Zi(String name ){
        super(name);
    }
}
​
​
​
/*
    父类没有无参的构造方法
 */
public class extendsTest2 {
    public static void main(String[] args) {
        //子类面向对象,先访问子类的无参构造方法
        Zi z = new Zi() ;
    }
}

1.5方法重写

方法重写
	如果子类和父类的成员方法不一样,分别调用即可
	如果子类的成员方法名和父类的成员方法相同,子类会将父类的方法进行覆盖
		---方法重写!
			---继承中使用,子类出现了和父类一模一样的成员方法,目的就是为了将父类中方法重写(覆盖)
注意事项
	子类的方法访问权限不能比父类低
public class Fu {
    public Fu(){
    }
    public void show(){
        System.out.println("父类会写java");
    }
}



public class Zi extends Fu {
    public void show(){
        System.out.println("子类不仅会java,还会写python!");
    }
    public void show1(){
        super.show();
    }
}



public class overRideTest {
    public static void main(String[] args) {
        Zi z = new Zi() ;
        z.show();
        z.show1();
    }
}

1.6final关键字

final关键字
	子类继承父类时,父类一些方法不需要或者不能让子类重写,为了保证数据的安全性
		---java提供了final关键字
			---final状态修饰符
				---最终的,无法更改的
public class Fu {
    public final void show(){
        System.out.println("这是不想被重写的一句话!");
    }
}



public class Zi extends Fu {
    //public void show(){ //报错,显示父类内容不可被修改!
    //    System.out.println("你必须被我重写!");
    //}
}



public class finalTest {
    public static void main(String[] args) {
        Zi z = new Zi() ;
        z.show();
    }
}
final关键字特点
	1)当final修饰类时,被修饰的类不能被继承!
	2)当final修饰成员变量时,被修饰的成员变量成为常量
		---只能被定义一次,之后不能被修改!
	3)当final修饰方法时,被修饰的方法不能被重写!
//final class Fu { //子类报错,不能继承被final修饰的类
public class Fu{
    int num = 10 ;
    final int num1 = 20 ;
    //num1 = 30 ;//报错,不能修改!
}



public class Zi extends Fu {
    public void show(){
        num = 50 ;
        //num1 = 30 ;//报错,子类也不能修改!
        System.out.println(num+", "+num1);
    }
}



public class finalTest1 {
    public static void main(String[] args) {
        Zi z = new Zi() ;
        z.num = 60 ;
        System.out.println(z.num);
        //z.num1 = 30 ;//报错,面向对象也不能修改!
        z.show();
    }
}

1.6.1面试题

final修饰基本数据类型和修饰引用类型区别?

分析
	final修饰基本数据类型后,基本数据类型的值就不会再改变
		---不能被赋值
	final修饰引用数据类型后,引用数据类型的空间地址值就不会再改变了
		---不能重新开辟内存空间---不能重新new
public class finalTest2 {
    public static void main(String[] args) {
        //final修饰基本数据类型
        int num = 10 ;
        num = 20 ;
        System.out.println(num);//num结果成功被修改
        final int num1 = 10 ;
        //num1 = 20 ;//报错,不能被修改!
        System.out.println(num1);//num1结果没有被修改
        System.out.println("-------------------------------");
        //final修饰引用数据类型
        Test t = new Test() ;
        System.out.println(t);//@1540e19d
        //开辟新的内存空间,新的空间地址值
        t = new Test() ;
        //输出空间地址值,创建新的成功
        System.out.println(t);//@677327b6
        final Test t2 = new Test() ;
        //t2 = new Test() ;//报错,不能改变空间地址值
        System.out.println(t2);
    }
}

2.多态(引入)(★)

多态
	现实世界---一个事物的多种形态
	java面向对象中
		多态---一个类体现出内存的变化
			---能够体现事物的不同形态
	前提条件
		1)必须有继承关系---无继承,不多态
		2)必须存在方法重写
		3)必须存在父类引用指向子类对象
			格式
				父类名 对象名 = new 子类名() ;
父类名 对象名 = new 子类名() ;
	多态成员访问特点
		1)成员变量
			编译看左,运行看左
		2)成员方法
			编译看左,运行看右---非静态的成员方法
				---静态的方法不算重写,可以直接类名调用!
		3)构造方法
			因为存在继承,构造方法在执行的时候,分层初始化,先让父类初始化,然后是子类构造初始化
多态的优势
	1)提高代码的扩展性
	2)提高代码的复用性和可维护性
多态的劣势
	父类名 对象名 = new 子类名 --->向上转型,无法访问子类特有的功能
				Fu f = new Fu() ;
解决方案
	向下转型---前提是必须有向上转型!
		将父类引用(对象名)强制转换成子类引用(对象名)
			---类似于基本数据类型之间的强制转换类型 
				---目标类型 变量名 = (目标类型)数据值 ;
		格式
			子类名 对象名 = (子类名)父类引用(对象名)
				Zi z = (Zi)f
public class Ainmal {
    private String name ;
    private int age ;
    private String color ;
//封装
    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 getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public Ainmal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    public Ainmal() {
    }
    public void eat(){
        System.out.println("动物都喜欢吃东西!");
    }
    public void sleep(){
        System.out.println("动物不得不睡觉!");
    }
}



public class Cat extends Ainmal {
    public Cat(String name, int age, String color) {
        super(name, age, color);
    }

    public Cat() {
    }
    //猫的特异功能
    public void washface(){
        System.out.println("猫洗脸");
    }
    //方法重载
    public void eat(){
        System.out.println("猫站着吃!");
    }
    public void sleep(){
        System.out.println("猫站着睡!");
    }

}



public class Dog extends Ainmal {

    public Dog(String name, int age, String color) {
        super(name, age, color);
    }

    public Dog() {
    }
    //狗特有的功能
    public void LookDoor(){
        System.out.println("狗看门");
    }
    //方法重写
    public void eat(){
        System.out.println("狗蘸着吃!");
    }
    public void sleep(){
        System.out.println("狗不睡觉!");
    }

}



//相当于创了一个调用Ainmal的类
public class AinmalTools {
    //禁止通过创建面向对象来访问此类
    private AinmalTools(){}
    //提供一个公共的调用方法,被static修饰可通过类名调用!
    public static void useAinmal(Ainmal a){
        a.eat();
        a.sleep();
    }
}



public class duotaiTest {
    public static void main(String[] args) {
        //测试
        //多态利用
        System.out.println("第一种方式");
        //父类名 对象名 = new 子类名() ;
        Ainmal a = new Cat() ;
        //调用的是Ainmal中的方法,但是堆内存中的是Cat
        a.eat();//猫站着吃!
        a.sleep();//猫站着睡!
        Ainmal a1 = new Dog() ;
        a1.eat();//狗蘸着吃!
        a1.sleep();//狗不睡觉!
        System.out.println("第二种更好的方式");
        Ainmal a2 = new Cat() ;
        //通过类名调用
        AinmalTools.useAinmal(a2);
        //输出结果:猫站着吃!
        //       猫站着睡!
        Ainmal a3 = new Dog() ;
        //将指向狗堆内存的地址传过去
        AinmalTools.useAinmal(a3);
        //输出结果:狗蘸着吃!
        //       狗不睡觉!
        System.out.println("----------------------------");
        //调用子类中的特有方法
        //向下转型
        //子类名 对象名 = (子类名)父类引用 ;(类比强制转换)
        Cat c = (Cat) a2 ;//将a2的空间地址值转换为Cat内存的,强制转换!
        //方法可以调用了
        c.washface();//猫洗脸
        Dog d = (Dog) a3 ;
        d.LookDoor();//狗看门
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到