Java基础之面向对象总结

引子:

      Python和Java都是面向对象的语言,本身都具有 封装 继承 多态,但2者之间还是存在一些差异,比如python直接支持多继承,java需要通过接口间接的实现多继承,所以感觉在学习Java的时候,不妨和python做个对比。

 

封装:

     Java的封装和Python有些不同,Java的最小颗粒是类,单Python可能就是个常量可以独立于类。另外最大的不同就是私有属性,像Java用private访问限定符来定义私有属性,访问的方法有直接访问和间接的方法,直接方法的话是需要定义同名的get set方法,间接的话需要在父类中实现成员方法来调用。但是在Python中常规的访问方法也是间接的,但是可以

通过  obj._类名__私有属性名 来访问,同样适用于继承

   Java:

public class testJJJ {
    private String name = "nihao";

    public String getName() {
        return name;
    }

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

public class testUUU {
    public static void main(String[] args) {
        testJJJ obj = new testJJJ();
        obj.getName();
    }
}

  Python:

class TestA:
    __private = 10
    a = 100

class TestB(TestA):
    pass

if __name__ == '__main__':
    # 子类强行调用父类私有属性
    obj=TestB()
    print(obj.__dir__())
    print(obj._TestA__private)
   # 父类强行调用自己私有属性
    obj_a = TestA()
    print(obj_a.__dir__())
    print(obj_a._TestA__private)

  方法定义:

    Java定义成员方法需要访问限定符,加private为私有方法,python只需要def关键字声明,前缀加双下划线表示私有方法,匿名函数除外。

            Java 的访问限定符:

public 公共的类似python的def
protected 收保护的,只供本类和所属子类使用
defalut 默认的这个不是关键字,直接声明方法就行
private 私有的,只供本类使用,但是不知道能不能像python一样强制调用

 

                  

 

         

 

 

 

                       权限修饰符横向和纵向对比:

  public protected defalut private
同一个类 y y y y
同一个包 y y y n
不同包但是存在继承关系 y y n n
不同包且存在继承关系 y n n n

 

 

 

 

 

        成员变量和成员方法:

           1、作用域以及优先级别

      同python基本一致,最近原则,找不到去找父类,是不包含多态的写法。java中的实例化如果是向上转型,成员方法编译看左,运行看右边,成员变量是编译看左,运行也看左。

    2、默认值:

      1、局部变量:没有默认值,需要手动赋值

      2、成员变量:如果没有赋值也是有默认值的,根据声明的数据类型 如 int 的默认值时0  double是0.0,String是null等,数组内元素默认值根据元素数据类型。

                  3、局部变量位于栈内存,成员变量位于堆内存。所以局部变量随着方法进栈而开始,随着方法出栈而结束。成员变量随着对象创建而诞生,随着垃圾回收而消失。

    

 

     调用方式:

     Python中方法加括号被调用,类加括号被实例化,对象加括号调__call__。但是java需要指定数据类型,并且使用new关键字来实例化对象,并且在Java中类是最小颗粒。

   

   赋值方式:

    Python中可以动态的给对象或者类增加动态或者静态属性,但是Java中没有定义的属性后期是不能添加的,也就是说java中不能无中生有。

 

   匿名对象:

    只有右边的对象没有左边的变量名和数据类型以及等号,匿名对象只能使用一次,下次再想使用需要重新创建对象。和python不同的是匿名对象可以作为入参,同Java相同的是匿名对象可以作为返回值

    

public class AnonymousStu {
    public static void main(String[] args) {
        FormatClass a=new FormatClass();
        a.addr="ljl";
        // 匿名对象
        new FormatClass().addr="test anonymous";
        System.out.println(testAonony(a));
        // 匿名参数可以在调用的时候传入参数
        testAonony2(new FormatClass());

        // 匿名参数作为返回值
        FormatClass testRet=testAonony3();

    }
    public static String testAonony(FormatClass b){
        return b.addr;
    }
    public static String testAonony2(FormatClass bbb){
        return bbb.addr;
    }
    public static FormatClass testAonony3(){
        return new FormatClass();
    }
}

  

public class FormatClass {
    private String name;
    private int age;
    public String addr;
    public FormatClass() {
    }

    public FormatClass(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;
    }
}

  

  java中的 static关键字和静态方法:

      Java的static和python的staticmethod装饰器很像,概念也基本一样,但是python中不能使用static去装饰静态属性。

                 Python

class TestC:
    @staticmethod
    def test_static():
        return 1

if __name__ == '__main__':
    print(TestC.test_static())

         Java

        在java中静态的总是优先于非静态的,用来一次性的静态变量赋值 一下demo中main方法就是static方法,private static int idCounter =0; 就是静态属性

public class UseStatic {
    public static void main(String[] args) {
        StaticStu one =new StaticStu("guo",44);
        StaticStu two =new StaticStu("aoteman",55);
        System.out.println("================================");
        System.out.println(one.getName());
        System.out.println(two.getName());
        System.out.println("================================");
        one.room="yonghui";
        System.out.println("班级:"+one.room+"学号"+one.getId());
        System.out.println("班级:"+two.room+"学号"+two.getId());

        System.out.println("================================");
        // 静态方法 不需要实例 直接调用 和python一样
        // 所以这个和  staticmethod  差不多太多 最好不在静态方法中 调用普通成员方法 因为这个按照python的理解 静态方法和类和实例都没有关系
        StaticStu.testStatic();

        // 静态代码块
        StaticCode a=new StaticCode();
        StaticCode aa=new StaticCode();

    }
}




public class StaticStu {
    private String name;
    private int age;
    static String room;
    private static  int idCounter =0;
    private int id;


    public StaticStu() {
        this.id=idCounter++;
    }

    public StaticStu(String name, int age) {
        this.name = name;
        this.age = age;

        // private static  int idCounter
        this.id=++idCounter;
    }

    public String getName() {
        System.out.println(StaticStu.idCounter);
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static void testStatic(){
        System.out.println("静态方法");
    }
    public void testDyn(){
        System.out.println("成员方法");
    }
}

  

  Java的类作为成员变量

    概念和python的组合类差不多,并且实现也差不多。           

    Java

      组合类

public class Hero {
    private String name; // 英雄名字
    private int age;
    private Wrapon weapon;

    public Hero(String name, int age, Wrapon weapon) {
        this.name = name;
        this.age = age;
        this.weapon = weapon;
    }

    public Hero() {
    }

    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 Wrapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Wrapon weapon) {
        this.weapon = weapon;
    }

    public void show(){
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.weapon.getCode());
        System.out.println("攻击敌方");
    }
}

    被组合类

public class Wrapon {
   private String code; //武器的代号

    public Wrapon(){

    }

    public Wrapon(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

     调用组合类

public class UseHero {
    public static void main(String[] args) {

        Hero hero = new Hero();
        hero.setName("盖伦");
        hero.setAge(44);


        // 创建武器对象
        Wrapon chuizi = new Wrapon("霜之哀伤");
        hero.setWeapon(chuizi);

        hero.show();
    }
}

  Python

class A:
    def test_a(self):
        return 1
class B:
    def __init__(self):
        self.obj = A
        self.obj2 = A()
if __name__ == '__main__':
    b_obj = B()
    print(b_obj.obj().test_a())
    print(b_obj.obj2.test_a())

  

  内部类:

    概念和python的类中类,方法类概念很像,java中由于最小颗粒是类所有就没有方法类。

    类型:

      1、成员内部类  内用外随意调用,外用内需要实例成员内部类调用

      2、局部内部类(匿名内部类) 定义在的成员方法中

    内外部类权限修饰符:

      1、外部类 public/(default)

      2、成员内部类 public/protected/(default)/private

      3、局部内部类什么都不写

      4、局部内部类 如果想要访问所属方法的局部变量 则这个变量必须是final的 

          原因:

            1 new出来的对象在对内存中

            2 局部变量是跟着方法走的在栈内存中

            3 方法运行之后  立即出栈 局部变量就会立即消失

              4 但是new出来的内部对象 会在对中持续纯在,知道gc销毁 所以这时候就需要全局变量

 

    Java

public class InnerCls {

     int a= 20;
     public void method(){
         System.out.println("外部类的方法");
         System.out.println(a);
     }
     public class Inner_cls{
         int a = 33;
         public void eat(){
             System.out.println("内部类的方法");
             method();
             System.out.println("内外部类 变量名重名 就近原则==========");
             System.out.println(a);
             // 不可以用 this 这里this指的是内部类
             System.out.println(this.a);
             // 内外部类出现重名方法 可以使用 外部类名.this.变量名
             System.out.println(InnerCls.this.a);
             System.out.println("内外部类 变量名重名 就近原则==========");
         }

     }
     public void testA(){
        Inner_cls innerobj = new Inner_cls();
         innerobj.eat();
     }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public void localInner(){
         // 如果一个局部内部类 希望访问所在方法的局部变量 则这个局部变量必须是final的 不写默认为final
         // java8 之后
         final int key = 0;
         class local_cls{
             String name= "局部内部类变量";
             public void testLocal(){
                 System.out.println("局部内部类");
                 System.out.println(key);
             }


          // 局部 内部类  只有该方法内部能使用
         }
         local_cls local_obj = new local_cls();
         local_obj.testLocal();
        System.out.println(local_obj.name);
    }
}



public class TestInnerCls {
    public static void main(String[] args) {

        // 间接调用 内部类
//        InnerCls obj = new InnerCls();
//        obj.testA();

        // 直接调用 内部类
        InnerCls.Inner_cls obj2 = new InnerCls().new Inner_cls();
        obj2.eat();


        // 调用局部内部类
        InnerCls obj4 = new InnerCls();
        obj4.localInner();

    }
}

  

 

   Python

class TestIner:
    class inner:
        def run(self):
            print("内部类的run方法")

    def test_a(self):
        a= 22
        class Fun_cls:
            def run(self):
                print(a)
                print("方法类")
        obj = Fun_cls()
        obj.run()
if __name__ == '__main__':
    obj = TestIner()
    obj.inner().run()
    obj.test_a()

  

   还有个比较特殊的叫匿名内部类:

   匿名内部类定义

/*
* 如果接口的实现类(或者是父类的子类)只需要使用唯一的一次
* 那么这种情况下可以省略掉该类的定义,而改为使用匿名内部类
*
*
* 匿名内部类:
*   1 格式 接口名称 对象名称 = new 接口名称(){ 覆盖重写所有的抽象方法 };
*                          new 代表创建对象的动作
*                          接口名称 就是倪敏内部类需要实现的借口
*                          {...} 这里才是匿名内部类的内容
*
*
*
* */


public class AnonymousnnerClass {
    public static void main(String[] args) {
//        UseFace impl = new UseFace();
//        impl.testA();


        // 直接使用 匿名内部类 直接new 接口 在内部重写所有抽象方法 在大括号中的就是一个类
        // 此匿名内部类 是写在 main 函数之中的 但是有变量名 不是匿名对象
         InterFaceAnony obj = new InterFaceAnony() {
             @Override
             public void testA() {
                 System.out.println("匿名内部类");
             }
         };
         obj.testA();

         // 另外一种匿名内部类写法  也是一种匿名对象.
        new InterFaceAnony(){

            @Override
            public void testA() {
                System.out.println("另外一种写法");
            }
        }.testA();

    }
}

  

 

  

 

继承:

    Java的继承和Python的继承还是有一些差异的,Java只支持单继承,但是接口可以支持多继承,Python本身就支持多继承。另外java中如果父类存在有参构造方法,子类需要显示的调用,否则默认调用父类的无参构造。同Python一样在Java中继承是多态的前提

 

     this 和 super的区别

      个人理解 this等同于python的self指的是实例的本身,super貌似和python一样指的事父类,可以直接调用父类的成员方法,不加this和super也可以,但是在子类的有参构造方法调用父类的有参构造方法中需要super(argstype args)

    

    重写:

      在python中只需要和父类的静态后者动态的方法名一致,就实现了重写覆盖,但是Java除了方法名一样之后,如果是成员方法还需要和父类的参数列表一致 @Override用来检测子类的重写是否正确

      需要注意的地方:

        1 子类和父类的方法名相同,且参数列表相同

        2 加上注解 @Override

        3 子类方法的返回值的数据类型必须小于等于父类同名方法的返回值

        4 子类方法的权限修饰符 必须大于等于 父类方法的权限修饰符

    

    子类和父类的同名属性优先级别

      这个和python一致,子类实例中有就用子类的,没有则调用父类的

 

     Java

       子类

public class extandStu extends demoClass {
    public static int aa = 10;

    @Test
    public void testIsBoolean() {
        System.out.println(super.isBoolean);
        int a =this.testEx(22);
        aa+=1;
        System.out.println(aa);
        //return a;
    }

    @Override // 用来检测 重写是否正确 建议加上
    public int testEx(int a){

        // 重写的方法 子类的返回值必须小于等于父类的返回值返回
        // return 3.55;
        return 66;
    }

    // 子类中的 返回值数据范围要小于 父类
    // python 没这样的要求
    // 猜想 python 中一切皆对象 声明变量的时候不需要指定数据类型 所有对象占用的内存是一样的 所以也就相当于java中重写的子类方法返回值要小于等于父类的返回值
    // 同时注意 返回值的 类型 基本数据类型 和 引用数据类型 下边的例子就是 基本数据类型
    @Override
    public String method(){
        //return "第三方";
        super.method();
        return "手动阀";

    }


    // 权限修饰符 public > protected > (default) 什么都不写 >private
    public int a;
    protected int b;
    // 什么都不写 默认defalut
    int c;
    private int d;


    public String ooxx(){

        System.out.println("sdfsdfsf");
        return "sdfsdf";
    }

    @Test
    @Override
    public void xxoo(){
        System.out.println("子类重写");
        super.xxoo();
        demoClass aa = new demoClass();
        aa.xxoo();
    }

    @Override  //若重写 idea快捷键 直接打父类方法就行
    public void xoxo() {
        super.xoxo();
    }
}

  父类

public class demoClass {
    public boolean isBoolean = true;
    public int testEx(int a){
        return a++;
    }

    public Object method(){
        return null;
    }

    Object ooxx(){
        return "sdf";
    }

    public void xxoo(){
        System.out.println("父类xxoo");
    }
    public void xoxo(){
        System.out.println("dsf");
    }
}

  

   抽象类

     1 、java直接用关键字指定 并且 抽象方法必须写在抽象类中, python中只要metaclass指定了了abc.ABCMeta那么这个类就是抽象类 抽象方法需要使用 @abc.abstractmethod装饰器

     2 、2者概念基本一致 都是一种规范

     3 、java的抽象类中能够定义成员方法 并且具体实现 python也可以

       4、java中抽象类可以有具体实现但是接口中不行,抽象类还可以有构造方法,本质上还是个类所以只能单继承

   

   注意事项:   

    * 1 不能直接 new 抽象类
    * 2 需要用子类继承抽象父类
    * 3 同python 一样 子类中必须要实现(等于重写)父类定义的抽象方法
    * 4 抽象类中可有有构造方法 是供子类创建对象时候 初始化父类成员使用的 子类的构造方法中的super
    * 5 抽象子类 中的方法 必须要重写 父类所有的抽象方法 除非 该子类也是 抽象类
    * (若一个抽象父类 有多个抽象子类,抽象子类没有定义新的抽象方法,则单个抽象子类并不需要全部实现父类全部抽象方法,可以只实现几个,甚至可以不实现,然后继承于抽象子类的普通孙类,可以实现抽象子类没有实现的抽象方法 
    * 6若抽象子类也定义了新的抽象方法:
      1 抽象子类没有实现抽象父类的抽象方法 则 普通孙类必须完全实现抽象子类和抽象父类的所有抽象方法
      2 抽象子类实现了部分抽象父类的抽象方法 则普通孙类则可以只实现抽象子类没有实现的抽象方法,包括抽象子类新定义的抽象方法
      3 抽象类不一定有抽象方法 只要保证抽象方法所在的类是抽象类 抽象类
   

   抽象父类

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

  抽象子类

public abstract class Dog extends Animal{
   @Override
   public void eat(){
       System.out.println("eat zilei ");
   }
   public abstract void run();
   public void test(){
       System.out.println("子类调用抽象父类普通方法");
   }
}

  实现类

public class DogGolden extends Dog{
    @Override
    public void sleep() {
        System.out.println("golden dog sleep");
    }
    public void run(){
        System.out.println("抽象子类的 抽象方法 in DogGolden");
    }


}

  调用实现类:

  

public class UseDog {
    public static void main(String[] args) {
        DogGolden golddong = new DogGolden();
        golddong.test();
    }
}

  

   Python

import abc

#抽象类
class AbstractClsDemo(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def read(self):
        pass

    @abc.abstractmethod
    def write(self):
        pass

    def run(self):
        print("抽象类中run")

# 实现类
class Test(AbstractClsDemo):
    def read(self):
        print('实现类read方法')

    def write(self):
        print('实现类write方法')

if __name__ == '__main__':
    obj = Test()
    obj.read()
    obj.write()
    obj.run()

  

   接口:

      同抽象类一样是一种规范,只要符合标准,就可以通用,是一种引用数据类型,最重要的就是其中的抽象方法,并且接口可以被类多继承

      格式:

        public interface 接口名称{  接口体  }

      

      java 7 8 9 接口可以包含的内容:

        1、常量

        2、抽象方法 abstract 声明

        3、java8 额外包含了 默认方法 和 静态方法

        4、java9 额外包含私有方法

        5、任何版本的java都可以定义抽象方法 

          

      注意事项:

        1、接口当中的抽象方法 修饰符是2个固定的关键字 public abstract 可以省略

        2、实现类的格式 public class_name implements interface_name{   }

        3、接口不能直接new 必须有一个实现类来实现该接口内抽象方法

        4、接口的实现类必须覆盖重写接口中定义的抽象方法

        5、若一个实现类不能完全覆盖掉接口中所有的抽象方法,那么这个实现类自己必须是抽象类

        6、成员变量 效果同常量 需要使用 public static final 修饰即使不写那么声明的变量也不能修改

        7、接口中不能有构造方法

      

      java8中的默认方法:

        1、和抽象方法不一样,默认方法有方法体,用来解决接口升级的问题,比如接口在后期有增加了一个抽象方法,那么继承该接口的子类都必须要实现,否则报错,但是在实际业务中显然不大可能,但是如果这个方法是用了默认方法,则不需要子类强制实现,但是增加了 抽象方法还是需要子类进行实现

        2、若多个接口类都有同名的默认方法,则子类必须要实现,否则不需要,可以直接调用

 

        java8中的静态方法

        1、调用接口的静态方法的格式   InterfaceClsName.静态方法(),这种静态方法同以上说的静态关键字static差不多,调用的时候需要通过接口名称直接调用,不能实例化接口

 

 

      Java

        2个接口类

public interface InterFaceA {

    public abstract void testA();
    public abstract void testAA();
    default void testDefault(){
        System.out.println("InterFaceA 默认方法");
    }
    public static void testStatic(){
        System.out.println("InterFaceA 的继承方法");
    }

}


public interface InterFaceB {
    public abstract void testB();
    public abstract void testBB();
    default void testDefault(){
        System.out.println("InterFaceA 默认方法");
    }
}

  

    一个实现类

 

public class ManyInterFace /*extends Object*/  implements InterFaceA,InterFaceB{
    @Override
    public void testA() {
        System.out.println("覆盖重写了 testA");
    }

    @Override
    public void testAA() {
        System.out.println("覆盖重写了 testAA");
    }

    @Override
    public void testB() {
        System.out.println("覆盖重写了 testB");
    }

    @Override
    public void testBB() {
        System.out.println("覆盖重写了 testBB");
    }

    @Override
    public void testDefault() {
    // 调用接口的静态方法 InterFaceA.testStatic(); System.out.println("多个接口 存在默认方法重名的时候 实现类必须要重写该重名默认方法"); } }

  

  调用实现类

public class UseManyInterFace {
    public static void main(String[] args) {
        ManyInterFace aa = new ManyInterFace();
        aa.testA();
        aa.testAA();
        aa.testB();
        aa.testBB();
        //InterFaceA.testDefaults();
        aa.testDefault();

    }
}

  

     

多态:

    Java的多态要比Python复杂一些,另外Python中是没有重载的,只要覆盖父类的同名属性就可以了,也不需要像Java那样参数列表还要一致。另外Java中的向上转型,向下转型Python也是没有的。

    重载: 

        重载指的是java的构造方法,重载的方法名同类名一致,然后根据入参的个数,数据类型,顺序来决定使用那个初始化方法,Python虽然没有这个,但是可以在构造方法中写判断决定怎样初始化。

      另外java的构造方法不能有返回值这一点倒是和python一样,如果不写构造方法编译器会默认生成一个无参数的构造方法,感觉还是调用的Object的,Python就是这样。

      需要注意的是 子类中 的无论有参无参构造方法都会默认调用父类的无参构造方法,如果要在子类的构造方法中调用父类的有参构造方法则需要手动调用 super(argsType args);

      java:

public class ClassInit {
    private String name;
    private int age;


    public ClassInit(String name,int age){
        System.out.println("构造方法不能写返回值 包括声明的时候不能使用 void 有参数 name---"+name+"----age=="+age);
        this.name=name;
        this.age=age;
    }
    public ClassInit(){
        System.out.println("构造方法不能写返回值 包括声明的时候不能使用 void");
        this.name="重载name";
        this.age=666;
    }

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

    }
    public String getName(){
        return this.name;
    }
    public void setAge(int age){
        this.age=age;
    }
    public int getAge(){
        return this.age;
    }
}

    Python

class TestA:
    def __init__(self,*args,**kwargs):
        if kwargs.get("flag") == 0:
            self.db =1
        elif kwargs.get("flag") == 1:
            self.db =2
        else:
            self.db=3

if __name__ == '__main__':
    obj = TestA(flag=0)
    print(obj.db)
    obj1 = TestA(flag=1)
    print(obj1.db)

  

  重写:

    重写肯定是在继承当中,java中方法名一样,参数列表也一样,才会覆盖,但是在python中只需要方法名一致就行了

    优先级别:

      1、如果new子类对象的时候,左侧是子类,则无论成员方法还是成员变量都是优先拿子类的

      2、如果new子类对象的是欧,左侧是父类,则成员方法,编译看左,运行看右。成员变量 编译看左,运行看左。

    Java:

    父类:

public class FatherClass {

    public int testA=10;
    public FatherClass()
    {
        System.out.println("父类无参构造 ");
    }
    public FatherClass(int a ,String b){
        System.out.println("父类有参构造方法");
        System.out.println(a);
        System.out.println(b);
    }

    public void testFunc(){
        System.out.println("父类testFunc");
    }

    子类:

public class OverrideInit extends FatherClass {

    public int testA = 22;


    public OverrideInit(){
        // 无参构造 调用 本类的有参 构造
        this(12,"sdf");
        System.out.println("子类无参构造 ");

    }
    public OverrideInit(int a,String b){
        // 需要手动 调用父类有参数构造 否则 调用无参构造
        super(a,b);
        System.out.println("子类有参构造方法");
        System.out.println(a);
        System.out.println(b);
    }
    public void testFunc(){
        System.out.println("子类testFunc");
    }
}

   调用子类:

public class testOverride {
    public static void main(String[] args){
        // OverrideInit a =new OverrideInit();
        // 正常实例化
        OverrideInit b =new OverrideInit(33,"sdf");
        // 这里调用子类成员变量
        System.out.println(b.testA);
        b.testFunc();

        System.out.println("---------");

        // 向上转型
        FatherClass obj = new OverrideInit(12,"sdf");
       // 这里调用父类的成员变量
        System.out.println("子类testA=22 父类testA=10 "+obj.testA);
        obj.testFunc();
    }


}            

  

 

  Java中 对象的向上和向下转型

      这是多态的一种表现形式,所谓向上和向下类之间必定有继承关系,

      向上转型

        所谓向上转型就是 左侧引用实例指向子类实例,且该对象可以被当作入参和返回值使用,不光是普通的类继承,接口和抽象类也是可以的

      向下转型

        所谓向下转性就是使用常规的new出来子类对象之后,在转成父类

        FaterCls obj = new SonCls();

        sonCls new_obj = (Soncls) obj; 有点类似数据类型强行转。 int a = 10; double b = (double) a;

      以上2种方式对成员方法和成员变量调用的影响:

        1、普通的:如果new子类对象的时候,左侧是子类,则无论成员方法还是成员变量都是优先拿子类的

        2、向上转型:如果new子类对象的时候,左侧是父类,则成员方法,编译看左,运行看右。成员变量 编译看左,运行看左。

          FaterCls obj = new SonCls();

        3、向下转型:先重复步骤3的到父类应用子类对象,在将父类引用转成子类引用。这时候无论左侧还是右侧都是子类,那无论成员方法还是变量都会优先调子类的

          FaterCls obj = new SonCls();

          SonCls new_obj=(Soncls) obj;

      java:

        定义usb接口 具备最基本的开启功能和关闭功能鼠标和键盘要能在电脑上使用 那么鼠标和键盘也必须遵循usb规范

      Usb类

public interface Usb {
    public abstract void open();
    public abstract void close();
    default void keyInput(){
        System.out.println("usb  键盘输入");
    }


}

    Computer类

public class Computer   {
    public void powerOn(){
        System.out.println("电脑开机");
    }
    public void powerOff(){
        System.out.println("电脑关机");
    }

    // 使用usb设备的方法
    public void useDevice(Usb usb){
        usb.open();
        usb.close();
    }

    public void keyInput(Usb usb){
       usb.keyInput();
    }

    public void useDevice2(Usb obj){
        // 使用向下转型实现 鼠标和键盘的独有功能
        if(obj instanceof KeyWrod){
            KeyWrod keyWrod_obj = (KeyWrod) obj;
            keyWrod_obj.keyInput2();
        }
        if(obj instanceof Mouse){
            Mouse mouse_obj = (Mouse) obj;
            mouse_obj.click();
        }

    }
}

    键盘类

public class KeyWrod implements Usb{
    @Override
    public void open() {
        System.out.println("打开键盘");
    }

    @Override
    public void close() {
        System.out.println("关闭键盘");
    }
    @Override
    public void keyInput(){
        System.out.println("键盘输入");
    }

    public void keyInput2(){
        System.out.println("键盘类独有的input方法");
    }

}

    鼠标类

public class Mouse implements Usb{
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }

    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }
    public void click(){
        System.out.println("鼠标点击");
    }
}

    调用实现类

public class demo {
    public static void main(String[] args) {
        Computer computer = new Computer();

        // 使用多态
        Usb keyword = new KeyWrod();
        Usb mouse = new Mouse();
        computer.powerOn();
        // 传入的是接口类型
        computer.useDevice(keyword);
        computer.useDevice(mouse);

        // 普通写法 不使用多态 传入实现类 支持向上转型 这里其实就是实现类向上转型了接口
        // 且  computer.useDevice 接受的参数 就是 接口Usb 类型 而keyword mouse是接口的实现类
        KeyWrod keyword1 = new KeyWrod();
        computer.keyInput(keyword1);
        computer.useDevice(keyword1);

        computer.powerOff();

        // 传入实现类 类似于 以下 也就是所java中可以传入下级 如果接受的是个大的数据类型 可以传入小的数据类型
        method(10.0);
        method(11);
    }


    public static void method(double num){
        System.out.println("static method  num==="+num);
    }
}

  

 

 
posted @ 2021-07-02 11:34  Yuan_x  阅读(67)  评论(0编辑  收藏  举报