疯狂Java学习笔记(012)

Since this day,I will write by my thoughts.

一、什么是多态?

  • 概念,Polaymorphosim,父类类型的变量引用了实现子类的一个对象。
  • 同样的变量,由于只想的子类对象不同,导致了同样的代码,执行结果不同!

二、引用数据类型的两个时期:

  1. 编译期类型,写在等号左侧,用来定义变量的类型
  2. 运行时类型,写在等号右侧,用来表示对象的类型
  •   例如:Animal aa = new Dog( ); 
  •   特点:左右不一致,有实现关系
  •   父类类型的变量引用子类的对象

三、多态的要求:

  1. 具有继承或者实现关系
  2. 编译期类型和运行类型不一致,即等号左右不一致
  3. 必须有方法的重写或方法实现

四、多态的好处

  通过配置文件、工厂模式获取一个实现子类对象,在不更改源码的情况下,更改.txt配置文件动态替换修改具体子类类名,就可以达到动态替换的目的。

/*

多态的案例,普通类多态
        
*/
class Animal{
    public void eat(){
        System.out.println("animal eat");
    }
}
class Dog extends Animal{
    
    public void eat(){
        System.out.println("dog eat");
    }
    
}

class Cat extends Animal{
    public void eat(){
        System.out.println("cat eat");
    }
}

public class PolymorphismDemo{
    public static void main(String[] args){
        //等号左右两侧的类型相同,不是多态!
        Animal a = new Animal();
        a.eat();
        
        //父类类型的变量引用子类的对象
        Animal aa = new Dog();
        aa.eat();        //此处执行的是子类重写的方法
        
        aa = new Cat();    //aa指向了一个Cat实例对象
        aa.eat();        //此处执行的是Cat类的eat方法
        
    }
}

五、抽象类多态

  1. 抽象类型 = new 实现子类型();
  • 编译期类型是抽象类类型;
  • 运行期类型是实现子类型;
  • 不能再为 Animal a = new Animal( );因为是抽象类型,只能为Animal a = new Dog( ); a.eat( );
  • 抽象类型调用的是子类中已经实现的方法;
/*
    抽象类多态
*/
abstract class Animal{
    public abstract viod eat();
}

class Dog extends Animal{
    public void eat(){
        System.out.println("dog eat");
    }
}
class Cat extends Animal{
    public void eat(){
        System.out.println("cat eat");
    }
}
public class PolyDemo2{
    public static void main(String[] args){
        // Dog d = new Dog();
        // d.eat();
        //抽象类多态
        Animal a = new Dog();
        a.eat();        //调用的是子类中已经实现的方法
        
        a = new Cat();
        a.eat();        //调用的是cat中的方法
        
    }
}

六、接口多态

编译期类型是接口类型,运行期是实现子类型

/*
    接口多态:
*/
interface InterA{
    public abstract void method();
}

class A implements InterA{
    public void method(){
        System.out.println("A method");
    }
}

class B implements InterA{
    public void method(){
        System.out.println("B method");
    }
}

public class PolyDemo3{
    public static void main(String[] args){
        //接口多态
        InterA a = new A();
        a.method();         //调用的是A实现子类的method方法
        
        //
        a = new B();
        a.method();            //调用的是B实现子类的method方法
    }
}

七、普通类之间有哪些成员多态性

  1. 成员变量没有多态性

  例如::Father f = new Son( );  下面调用f.age 其实还是父类自己的age,不会因为子类也有age而返回子类的值。

  2. 静态方法没有多态性

  例如:定义父类中静态方法,public static void test2(){System.out.println("  father ")}即使子类也有,当Father f = new Son( ); f.test2();调用的还是父类的静态成员方法。

  3.父类类型的变量无法引用子类特有的方法

  例如:子类特有test3( );方法,子类再继承父类已有的方法基础上,父类无法调用,编译报错。

  程序执行过程:编译期,会检查父类方法的定义;编译期,看子类是否重写。

  • 如果方法父类没有,子类有则编译报错;
  • 如果方法父类有,子类重写的情况,执行子类。如果子类未重写情况,执行父类。
/*
演示:
  普通之间,哪些成员有多态性?
  方法调用:
  引用数据类型的转换:
*/ class Father{ //成员变量 public int age = 30; //普通的成员方法 public void test(){ System.out.println("father test"); } //静态方法 public static void test2(){ System.out.println("father test2"); } } class Son extends Father{ // public int age = 10; // public void test(){ // System.out.println("son test"); // } //静态方法 public static void test2(){ System.out.println("son test2"); } //子类特殊的方法 public void test3(){ System.out.println("子类特有的方法"); } } public class PolyDemo4{ public static void main(String[] args){ Father f = new Son(); // f.test(); //调用的是子类重写之后的方法 // System.out.println(f.age); //成员变量没有多态性!! // f.test2(); //成员方法没有多态性!! // f.test3(); //类型不对 //把f变量强转成子类型 Son s = (Son)f; //引用数据类型强转的前提: //1.必须有继承关系 //2.必须真实指向的对象类型和要赋值的数据类型匹配!! s.test3(); //简写:.的优先级高于()优先级 ((Son)f).test3(); } }

八、引用数据类型转换

  1. 向上转换:即子类→父类,自动转换

  书写格式:Father f = new son( );

       f.test3();

  强制转换:Son s = (son)f;

       s.test3();

      也可简写为:(Son(f)).test3(),其中,“ . ”的优先级大于“()”的优先级

  2.向下转换:即父类→子类,强制转换

  存在前提:①存在子父类关系,即有继承关系。

       ②必须真实指向的对象类型和要赋值的数据类型匹配

       例如:Animal a = new Dog( );

          Cat c = (Dog)a;

          这种情况就是错的。

  书写格式:Father f = new son( );

       Son s = (son)f;

       s.test3();

      也可简写为:(Son(f)).test3(),其中,“ . ”的优先级大于“()”的优先级。

九、内部类

  概念:内部类又称内置类、嵌套类,就是在一个类的内部定义的类。

class Outer{
    //成员内部类    
    public class Inner{
        public void method(){
            System.out.println("Inner class method");
        }
    }
    //局部内部类
    public void test(){
        class Inner2{
            public void method(){
          //int a = 10; System.out.println(
"Inner2 class method");
          //System.out.print(a++) } } } }

说明:代码中,Inner为成员内部类,Inner2为局部内部类(在方法内部)

  1. 局部内部类(不常用)

  其中,在局部内部类中如果上面代码,里面加a++,会报错,原因是局部内部类中定义的变量是final形式,不可以编号。

  2. 成员内部类

  可以包含成员方法、构造方法、成员变量。

class Outer{
    
    private int age = 10;
    
    //成员位置定义内部类:
    public class Inner{
        public void method(){
            System.out.println(++age);    //11
            System.out.println(age);    //11
            System.out.println("Inner class method");
        }
    }  

调用外部类的方法,new Inner().method();  new+外部类名+内部类名

  3.访问特点:①内部类可以直接访问外部类中的成员,包括私有成员;

          如上面代码里,private int age = 10,Inner里就可以直接使用。

        ②外部类要访问内部类中的成员必须要求建立内部类的对象。如

    //内部类创建对象
    public void test2(){
        //创建内部类对象,调用内部类的方法
        new Inner().method();
    }
public class InnerDemo1{
    public static void main(String[] args){
        //调用外部类方法,
        new Outer().test2();
        
        //局部内部类调用
        // new Outer().test();
    }
}

  4.我们已知四种权限修饰符:protectedpublicpriviate默认

  5.运行后,文件中会多Out$Inner2.class的字节码文件,就是内部类的字节码文件。

十、非静态成员内部类和静态成员内部类

  1. 非静态成员的内部类,能定义非静态成员,不能定义静态成员,但都能使用;

  2.静态成员的内部类,能定义非静态和静态,但只能使用静态,不能使用非静态;

  3.使用方法:

    非静态:Outer.Inner il = new Outer().new Inner();

        il.show();

    静态:    Outer.Inner il = new Outer().new Inner();

        il.show();

十一、匿名内部类

  1.匿名内部类适用于这个类只使用一次的情况,不适用这个内部类被多次使用的情况

  2.使用匿名内部类的前提:
     内部类可以继承或实现一个外部类或者接口
    什么情况下,内部类只被使用一次呢?
     最常见的就是方法的形参列表上
  格式1:
    new 接口名() {
         //匿名内部类的类体:通常是实现抽象方法
    }
  格式2:
    new 父类名(形参列表){
         //匿名内部类的类体:通常是实现抽象方法
    }
从以上格式可以看出:

  1. 匿名内部类不能是抽象类,必须实现所有抽象方法
  2. 匿名内部类不能有构造方法,因为它没有名字
  3. 内部类实现接口时,只能加(),继承一个抽象类时,父类名后可以指定抽象类的构造方法
/*
    匿名内部类:    
*/

abstract class Animal{
    
    public abstract void eat();
}

class Test{
    public void test(Animal an){
        an.eat();
    }
}

/*
class Dog extends Animal{
    public void eat(){
        System.out.println("dog test");
    }
}

*/
public class InnerDemo3{
    /*
    //成员内部类:继承外部的抽象类
    private static class Dog extends Animal{
        public void eat(){
            System.out.println("dog test");
        }
    }
    */
    
    public static void main(String[] args){
        // Dog d = new Dog();
        // new Test().test(d);
        
        //匿名内部类方式创建对象,传递给方法
        new Test().test(new Animal(){
            public void eat(){
                System.out.println("dog eat");
            }
        });
    }
}

-----------------------------------------------------------------------------------------------------------

中午练习:

设计两个方法:参数分别是一个普通类和接口类型,然后在调用的时候,直接创建一个该普通类的匿名子类和接口的匿名实现子类当成参数传递.
/*
    方法的参数是一个普通类,调用方法时临时创建一个子类对象.
    
*/
class Father{
    public Father(){
        System.out.println("父类的空参构造方法");
    }
    
    public Father(int a){
        System.out.println("父类的带参构造方法");
    }
    
    public void method(){
        System.out.println("father method");
    }
}

class Test{
    public void test(Father f){
        f.method();
    }
}

public class InnerDemo5{
    public static void main(String[] args){
        // Father f = new Father();
        // new Test().test(f);
        //调用方法时,临时创建一个没名的子类对象!
        new Test().test(new Father(0){            //父类是普通类,或抽象类,可以指定父类的构造方法!!
                                                //如果是接口,什么都不能写!!
            //重写父类的method方法
            public void method(){
                System.out.println("overwrite method");
            }
        });
    }
}
/*
    接口类型的参数方法,调用方法时,临时生成一个此接口的实现子类的对象!!!
    
*/

interface InterA{
    public abstract void method();
}

class Test{
    public void test(InterA a){
        a.method();
    }
}
public class InnerDemo6{
    public static void main(String[] args){
        new Test().test(new InterA(){
            //实现接口中所有的抽象方法
            public void method(){
                System.out.println("实现子类的方法");
            }
        });
    }
}

---------------------------------------------------------------------------------

/*
    匿名内部类给接口类型变量赋值
    
*/
interface InterA{
    public abstract void show();
    
}
public class InnerDemo7{
    public static void main(String[] args){
        //创建一个实现了InterA接口的实现子类对象,并赋值给接口类型的变量
        InterA a = new InterA(){   //接口多态:        = 左边是接口类型的变量
                                    //                = 右边是接口的实现子类的对象
            //
            public void show(){
                System.out.println("子类实现了接口的方法");
            }
            //
        };
        
        //
        a.show();   //此处调用的是实现子类的实现方法!!!
        
    }
}

 

 

  

原文地址:https://www.cnblogs.com/akinodoo/p/9896215.html