【JAVA基础】08 面向对象3

1. 多态

  • 多态polymorhic概述

    • 事物存在的多种形态。
  • 多态前提
    • 要有继承关系
    • 要有方法重写
    • 要有父类引用指向子类对象
  • 案例演示
    • 代码体现多态
    • class  Demo1_Polymorphic{
          public static void main(String[] args) {
              Cat c = new Cat();
              c.eat();
      
              Animal a = new Cat(); // 父类引用指向子类对象
              a.eat();  // 输出“猫吃鱼”
          }
      }
      
      
      class Animal {
          public void eat() {
              System.out.println("动物吃饭");
          }
      }
      
      class Cat extends Animal {
          public void eat() {
              System.out.println("猫吃鱼");
          }
      }
  • 多态中的成员访问特点
    • 成员变量
      • 编译看左边(父类),运行看左边(父类)
      • Father f = new Son();
      • class Demo2_Polymorphic {
            public static void main(String[] args) {
                Father f = new Son();
                System.out.println(f.num); //输出10
            }
        }
        
        class Father {
            int num = 10;
        
        }
        
        class Son extends Father {
            int num = 20;
        }

         

         如果再上面例子的基础上,再生成一个Son类对象,则

      • class Demo2_Polymorphic {
            public static void main(String[] args) {
                Father f = new Son();
                System.out.println(f.num); //输出10
        
                Son s = new Son();
                System.out.println(s.num);   //输出20
            }
        }
        
        class Father {
            int num = 10;
        
        }
        
        class Son extends Father {
            int num = 20;
        }

         

    • 成员方法
      • 编译看左边(父类),运行看右边(子类)——又称“动态绑定”
      • Father f = new Son();
      • 编译时,看父类中有没有该成员方法,有则编译成功;运行则动态绑定到子类的成员方法上,运行子类的成员方法。
      • class Demo3_Polymorphic {
            public static void main(String[] args) {
                Father f = new Son();
                f.print();// 输出son
            }
        }
        
        class Father {
            int num = 10;
        
            public void print() {
                System.out.println("father");
            }
        
        }
        
        class Son extends Father {
            int num = 20;
        
            public void print() {
                System.out.println("son");
            }
        }

         

    • 静态方法
      • 编译看左边(父类),运行看左边(父类)
      • 静态和类相关,算不上重写,所以,访问还是左边的
      • class Demo4_Polymorphic {
            public static void main(String[] args) {
                Father f = new Son();
                f.method();  //输出"father static method";
                // 相当于是Father.method(); 调用父类的方法
            }
        }
        
        class Father {
            int num = 10;
        
            public void print() {
                System.out.println("father");
            }
        
            public static void method(){
                System.out.println("father static method");
            }
        
        }
        
        class Son extends Father {
            int num = 20;
        
            public void print() {
                System.out.println("son");
            }
        
            public static void method(){
                System.out.println("son static method");
            }
        }
    • 总结:
      • 只有非静态的成员方法,编译看左边(父类),运行看右边(子类)
      • 其他都是编译看左边(父类),运行看左边(父类)
  • 案例:超人的故事
    • 通过该案例帮助理解多态的现象。
    • class Demo5_Polymorphic {
          public static void main(String[] args) {
              Person p = new SuperMan(); // 父类引用指向子类对象,超人提升为人
      
              System.out.println(p.name);// 输出“John”
              p.谈生意();  // 输出"谈几个亿的大单子"
              
              
              //p.fly();  //编译出错
              
          }
      }
      
      class Person {
          String name = "John";
      
          public void 谈生意() {
              System.out.println("谈生意");
          }
      }
      
      class SuperMan extends Person {
          String name = "Super man";
      
          public void 谈生意() {
              System.out.println("谈几个亿的大单子");
          }
      
          public void fly() {
              System.out.println("飞出去救人");
          }
      }
      View Code

超人作为人类身份的属性信息对外展示,Person类和SuperMan类中重写的方法,实际执行的是超人身份的方法;

在这个例子中,父类中没有fly方法,故编译失败,也无法执行。针对这个,要考虑下面的 向上转型和向下转型 的问题。
  • 多态中 向上转型和向下转型
    • 向上转型
      • Person p = new SuperMan();
      • 父类引用指向子类对象,就是向上转型
    • 向下转型
      • SuperMan sm = (SuperMan)p;
      • class Demo5_Polymorphic {
            public static void main(String[] args) {
                Person p = new SuperMan(); // 父类引用指向子类对象,超人提升为人
        
                System.out.println(p.name);// 输出“John”
                p.谈生意();  // 输出"谈几个亿的大单子"
                
                
                //p.fly();  //编译出错
        
                SuperMan sm = (SuperMan)p; // 向下转型
                sm.fly();
                
            }
        }
        
        class Person {
            String name = "John";
        
            public void 谈生意() {
                System.out.println("谈生意");
            }
        }
        
        class SuperMan extends Person {
            String name = "Super man";
        
            public void 谈生意() {
                System.out.println("谈几个亿的大单子");
            }
        
            public void fly() {
                System.out.println("飞出去救人");
            }
        }

  • 补充参考:基本数据类型:
    • 自动类型提升
    • 强制类型转换
    • class  Demo1_Polymorphic{
          public static void main(String[] args) {
              int i = 10;
              byte b = 20;
              i = b;  // 自动类型转换
              b = (byte)i;  // 强制类型转换
              
          }
      }
  • 多态的好处和弊端
    • 多态的好处
      • 提高了代码的维护性(继承保证)
      • 提高了代码的扩展性(由多态保证)
        • 可以当做形式参数
        • 可以接收任意子类对象
    • 多态的弊端
      • 不能使用子类的特有属性和行为
    • 案例演示
      • method(Animal a)  方便Animal的所有子类的 重写的方法调用
      • method(Cat c)  这种直接调用子类,出现并行子类,调用父类方法,需要些新的method方法,传入不同的类作为实参。
      • class Demo6_Polymorphic {
            public static void main(String[] args) {
                
                method(new Cat());
                method(new Dog());  
                /* 
                Animal a = new Cat();
                Animal a = new Dog();
                
                开发的时候很少在创建对象的时候用父类引用指向子类对象,
                直接创建子类对象更方便,可以使用子类中的特有属性和方法
                
                */
        
            }
        
            /*
            public static void method(Cat c) {
                c.eat();
            }
        
            public static void method(Dog d) {
                d.eat();
            }*/
        
            public static void method(Animal a) { // 当做参数的时候,用多态最好,扩展性强
                //关键字 instanceof 判断前边的引用是否是后边的数据类型
                if (a instanceof Cat) {
                    Cat c = (Cat)a;
                    c.eat();
                    c.catchMouse();
                }else if (a instanceof Dog) {
                    Dog d = (Dog)a;
                    d.eat();
                    d.lookHome();
                }else {
                    a.eat();
                }
        
                
                /*
                // 如果把Dog强转成Cat,就会出现类型转换异常,ClassCastException
                Cat c = (Cat)a;
                c.eat();
                c.catchMouse();*/
            }
        }
        
        class Animal {
            public void eat() {
                System.out.println("动物吃饭");
                }
        }
        
        class Cat extends Animal {
            public void eat() {
                System.out.println("猫吃鱼");
            }
        
            public void catchMouse() {
                System.out.println("抓老鼠");
            }
        }
        
        class Dog extends Animal {
            public void eat() {
                System.out.println("狗吃肉");    
            }
        
            public void lookHome() {
                System.out.println("看家");
            }
        }
        View Code 

2. 抽象类

  • 抽象类概述
    • 抽象就是看不懂的
  • 抽象类的特点
    • 抽象类和抽象方法必须用abstract关键字修饰
      • abstract class 类名 ()
      • public abstract void eat();
    • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者接口
    • 抽象类不能实例化,那么,抽象类如何实例化呢?
      • 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
    • 抽象类的子类
      • 要么是抽象类
      • 要么重写抽象类中的所有抽象方法
    • 案例演示
      • class Demo1_Abstract {
            public static void main(String[] args) {
        
                Animal a = new Cat();
                a.eat();
                print(a);
            }
        
            public static void print(Animal a) {
                a.eat();
            }
        }
        
        
        abstract class Animal { // 抽象类
             public abstract void eat();  // 抽象方法
        }
        
        
        class Cat extends Animal {
        
            public void eat() {
                System.out.println("猫吃鱼");
            }
        
        }
        View Code
      • class Demo1_Abstract {
            public static void main(String[] args) {
        
                
            }
        
            public static void print(Animal a) {
                a.eat();
            }
        }
        
        
        abstract class Animal { // 抽象类
             public abstract void eat();  // 抽象方法
        }
        
        class Cat extends Animal {
        
            //错误: Cat不是抽象的, 并且未覆盖Animal中的抽象方法eat()
        
        }
        View Code
    • 抽象类联系(猫狗,抽象类为动物)
      • 具体事物:猫,狗
        共性:姓名,年龄,吃饭
        猫的特性:抓老鼠
        狗的特性:看家

      • class Test1_Animal {
            public static void main(String[] args) {
                Cat c = new Cat("加菲",8);
                System.out.println(c.getName() + "..." + c.getAge());
                c.eat();
                c.catchMouse();
        
                Dog d = new Dog("八公",30);
                System.out.println(d.getName() + "..." + d.getAge());
                d.eat();
                d.lookHome();
        
        
            }
        }
        
        /*
        案例演示:
        具体事物:猫,狗
        共性:姓名,年龄,吃饭
        猫的特性:抓老鼠
        狗的特性:看家
        */
        
        abstract class Animal {
            private String name;
            private int age;
        
            public Animal(){}
        
            public Animal(String name,int age) {
                this.name = name;
                this.age = age;
            }
        
            public void setName(String name) {  // 设置姓名
                this.name = name;
            }
        
            public String getName() { // 获取姓名
                return name;
            }
        
        
            public void setAge(int age) {  // 设置年龄
                this.age = age;
            }
        
            public int getAge() { // 获取年龄
                return age;
            }
        
        
            public abstract void eat();  // 抽象方法:吃饭
        }
        
        
        class Cat extends Animal {
            public Cat(){}
        
            public Cat(String name,int age) {
                super(name,age);
            }
        
            public void eat() {
                System.out.println("猫吃鱼");
            }
        
            public void catchMouse() {
                System.out.println("抓老鼠");
            }
        }
        
        
        class Dog extends Animal {
            public Dog(){}
        
            public Dog(String name,int age) {
                super(name,age);
            }
        
            public void eat() {
                System.out.println("狗吃肉");
            }
        
            public void lookHome() {
                System.out.println("抓老鼠");
            }
        }
        View Code
      • class Test2_Teacher {
            public static void main(String[] args) {
                Teacher t = new BaseTeacher();
                print(t);
        
                print(new EmpTeacher());
                
            }
            
            public static void print(Teacher t) {
                t.teach();
            }
        }
        
        /*
        具体事物:基础班老师,就业班老师
        共性:姓名、年龄、讲课
        */
        
        abstract class Teacher {
            private String name;
            private int age;
            
            public abstract void teach();
        
        
            public Teacher() {}
        
            public Teacher(String name, int age) {
                this.name = name;
                this.age = age;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getName() {
                return name;
            }
        
            public void setAge(int age) {
                this.age = age;
            }
        
            public int getAge() {
                return age;
            }
        
        }
        
        class BaseTeacher extends Teacher {
            public BaseTeacher() {}
        
            public BaseTeacher(String name, int age) {
                super(name, age);
            }
        
        
            public void teach() {
                System.out.println("基础班老师 讲课");
            }
        
        }
        
        
        class EmpTeacher extends Teacher {
            public EmpTeacher() {}
        
            public EmpTeacher(String name, int age) {
                super(name, age);
            }
        
        
            public void teach() {
                System.out.println("就业班老师 讲课");
            }
        
        }
        老师抽象类
      • class Test3_Student {
            public static void main(String[] args) {
                state(new BaseStudent());
                state(new EmpStudent());
            }
        
            public static void state(Student s) {
                s.study();
            }
        }
        
        
        /*
        具体事物:基础班学生,就业班学生
        共性:姓名,年龄,学习
        */
        
        abstract class Student {
            private String name;
            private int age;
            
            public abstract void study();
        
            public Student() {}
        
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getNamge() {
                return name;
            }
        
            public void setAge(int age) {
                this.age = age;
            }
        
            public int getAge() {
                return age;
            }
        
        }
        
        class BaseStudent extends Student {
            public BaseStudent() {}
        
            public BaseStudent(String name, int age) {
                super(name,age);
            }
        
            public void study() {
                System.out.println("基础班学生在学习");
            }
        }
        
        class EmpStudent extends Student {
            public EmpStudent() {}
        
            public EmpStudent(String name, int age) {
                super(name,age);
            }
        
            public void study() {
                System.out.println("就业班学生在学习");
            }
        }
        学生抽象类
      • class Test4_Employee {
            public static void main(String[] args) {
                Coder c = new Coder("John", "001", 10000.00);
                c.work();
        
                Manager m = new Manager("Ann", "033", 40000.00, 10000);
                m.work();
                
            }
        }
        
        /*
        假如我们在开发一个系统时,需要对程序员类进行设计。
        程序员包含3个属性:
            姓名
            工号
            工资
        
        经理:出了含有程序员的属性外,还有一个奖金属性
        
        用继承的思想设计出程序员类和经理类。
        要求类中提供必要的方法进行属性访问。
        
        */
        
        abstract class Employee {
            private String name;
            private String code;
            private double salary;
        
            public Employee() {}
        
            public Employee(String name, String code, double salary) {
                this.name = name;
                this.code = code;
                this.salary = salary;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getName(){
                return name;
            }
        
            public void setCode(String code) {
                this.code = code;
            }
        
            public String getCode(){
                return code;
            }
        
            public void setSalary(double salary) {
                this.salary = salary;
            }
        
            public double getSalary(){
                return salary;
            }
        
            public abstract void work();
        
            
        }
        
        
        class Manager extends Employee {
            private int bonus;
        
            public Manager() {}
        
            public Manager(String name, String code, double salary, int bonus) {
                super(name,code,salary);
                this.bonus = bonus;
            }
        
            public void setBonus(int bonus) {
                this.bonus = bonus;
            }
        
            public int getBonus(){
                return bonus;
            }
            
            
            public void work() {
                System.out.println("项目经理" + this.getName() + "在工作");
                System.out.println("奖金是" + this.getBonus());
            }
        
        }
        
        
        class Coder extends Employee {
            public Coder() {}
        
            public Coder(String name, String code, double salary) {
                super(name,code,salary);
            }
            
            public void work() {
                System.out.println("程序员" + this.getName() + "在工作");
            }
        
        }
        雇员:程序员,项目经理
  • 抽象类的注意问题
    • 一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
      • 可以。
        目的只有一个,就是不让其他类创建本类对象,交给子类完成
    • abstract不能和哪些关键字共存?

      • abstract 和 static
        被abstract修饰的方法没有方法体;
        被static修饰的可以用 类名.调用,但是类名.调用 抽象方法是没有意义的。

      • abstract 和 final 
        被abstract修饰的方法强制子类重写;
        被final修饰的方法,不让子类重写。这两个修饰词是矛盾的。

      • abstract 和 private
        被abstract修饰的是为了让子类看到并强制重写
        被private修饰的不让子类访问,所以他两是矛盾的。

      • class Demo4_Abstract {
            public static void main(String[] args) {
                System.out.println("Hello World!");
            }
        }
        
        
        /*
        面试题1:
            一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
        答:
            可以。
            目的只有一个,就是不让其他类创建本类对象,交给子类完成
        
        面试题2:
            abstract不能和哪些关键字共存?
        答:
            abstract 和 static
            被abstract修饰的方法没有方法体;
            被static修饰的可以用 类名.调用,但是类名.调用 抽象方法是没有意义的。
        
            abstract 和 final 
            被abstract修饰的方法强制子类重写;
            被final修饰的方法,不让子类重写。这两个修饰词是矛盾的。
        
            abstract 和 private
            被abstract修饰的是为了让子类看到并强制重写
            被private修饰的不让子类访问,所以他两是矛盾的。
        
        
        */
        
        abstract class Demo {
            // public static abstract void print();
            // Demo4_Abstract.java:21: 错误: 非法的修饰符组合: abstract和static
            
            // public final abstract void print();
            // Demo4_Abstract.java:29: 错误: 非法的修饰符组合: abstract和final
            
            // private abstract void print();
            // Demo4_Abstract.java:36: 错误: 非法的修饰符组合: abstract和private
        }
        View Code

3. 接口

  • 接口概述
    • 从狭义的角度讲,就是指java中的interface
    • 从广义的角度讲,就是对外提供规则的都是接口
  • 接口特点
    • 接口关键字interface表示
      • interface 接口名 {}
    • 类实现接口用 implements表示
      • class 类名 implements 接口名 {}
    • 接口不能实例化
      • 那么,接口如何实例化呢?
      • 按照多态的方式来实例化
    • 接口的子类
      • 可以是抽象类,但是意义不大。
      • 可以使具体类,要重写接口中的所有抽象方法(推荐方案)
  •  案例演示:接口特点
    • class Demo1_Interface {
          public static void main(String[] args) {
          //Inter i = new Inter();  // 接口不能被实例化,因为调用抽象方法没有意义
      
          Inter i = new Demo();
          i.print();
      
          }
      }
      
      interface Inter {
          public abstract void print(); // 接口中的方法都是抽象的
      }
      
      class Demo implements Inter {
          public void print() {
              System.out.println("print");
          }
      }
      接口类-子类是具体类,重写接口的 抽象方法(推荐)
    • class Demo1_Interface {
          public static void main(String[] args) {
      
      
          }
      }
      
      interface Inter {
          public abstract void print(); // 接口中的方法都是抽象的
      }
      
      abstract class Demo implements Inter {
          
      }
      接口-子类是抽象类(不推荐)
  • 接口的成员特点:

    • 成员变量

      • 只能是常量,并且是静态的,并公共的。
      • 默认修饰符:public static final(即使不手写,也会默认添加)
      • 建议:自己手动给出
    • 构造方法

      • 接口没有构造方法
    • 成员方法 

      • 只能是抽象方法
        • 默认修饰符:public abstract
        • 建议:自己手动给出
    • 案例演示
      • class Demo1_Interface {
            public static void main(String[] args) {
            
            Demo d = new Demo();
            d.print();
        
            System.out.println(Inter.num);
        
            }
        }
        
        interface Inter {
            public static final int num = 10;  // 系统会默认添加public static final,建议手动写出
            // 这三个关键词没有顺序区别
        
            // public Inter(){} 报错,接口中没有构造方法
            
            // public void print() {} // 接口中不能定义非抽象方法
        
            void print(); // 前面默认添加了public abstract修饰词
            public abstract void print2();
        }
        
        class Demo /* extends Object */ implements Inter {  // 一个类不写继承任何一个类,默认继承Object类
            public void print() {
                
                System.out.println(num);
            }
        
            public void print2() {}
        }
        View Code
      • class Test1_Aniaml {
            public static void main(String[] args) {
                Cat c = new Cat("加菲",8);
                c.eat();
                c.sleep();
        
                JumpCat jc = new JumpCat("跳高猫",3);
                jc.eat();
                jc.sleep();
                jc.jump();
            }
        }
        
        /*
        动物类:姓名,年龄,吃饭,睡觉
        
        猫和狗
        
        动物培训接口:跳高
        */
        
        abstract class Animal {
            private String name;
            private int age;
        
            public Animal(){}
            public Animal(String name,int age){
                this.name = name;
                this.age = age;
            }
        
            public void setName(String name){
                this.name = name;
            }
        
            public String getName(){
                return name;
            }
        
            public void setAge(int age){
                this.age = age;
            }
        
            public int getAge(){
                return age;
            }
        
            public abstract void eat();
        
            public abstract void sleep();
        
        }
        
        interface Jumping {
            public void jump();
        }
        
        class Cat extends Animal {
            public Cat(){}
            public Cat(String name,int age){
                super(name,age);
            }
        
            public void eat() {
                System.out.println("猫吃鱼");
            }
        
            public void sleep() {
                System.out.println("侧着睡");
            }
        
        }
        
        class JumpCat extends Cat implements Jumping {
            public JumpCat(){}
            public JumpCat(String name,int age){
                super(name,age);
            }
        
            public void jump() {
                System.out.println("猫跳高");
            }
        
        }
        动物:猫类,跳高的接口

3. 各种类,接口之间的关系

3.1 类与类,类与接口,接口与接口的关系

  • 类与类
    • 继承关系
      • 只能单继承,可以多层继承
  • 类与接口
    • 实现关系,可以单实现,也可以多实现
    • 并且还可以在继承一个类的同时实现多个接口
    • class Demo1_Interface {
          public static void main(String[] args) {
      
          }
      }
      
      
      
      interface InterA {
          public abstract void printA();
      }
      
      interface InterB {
          public abstract void printB();
      }
      
      class Demo implements InterA,InterB {
          public void printA() {
              System.out.println("printA");
          }
      
          public void printB() {
              System.out.println("printB");
          }
      }
      View Code
  • 接口与接口
    • 继承关系
      • 可以单继承,也可以多继承。
      • class Demo1_Interface {
            public static void main(String[] args) {
        
            }
        }
        
        
        
        interface InterA {
            public abstract void printA();
        }
        
        interface InterB {
            public abstract void printB();
        }
        
        interface InterC extends InterA,InterB {
        }
        View Code

 3.2 抽象类和接口的区别

  • 成员区别
    • 抽象类
      • 成员变量:可以变量,也可以常量
      • 构造方法:有
      • 成员方法:可以抽象,也可以非抽象
    • 接口
      • 成员变量:只可以常量
      • 成员方法:只可以抽象
  • 关系区别
    • 类与类
      • 继承,单继承
    • 类与接口
      • 实现,单实现,多实现
    • 接口与接口
      • 继承,单继承,多继承
  • 设计理念区别
  • 抽象类
    • 被继承体现的是“is a”的关系。
    • 抽象类中定义的是该继承体系的共性功能
  • 接口
    • 被实现体现的是“like a”的关系。
    • 接口中定义的是该继承体系的扩展功能

4. 包package

  • 为什么要有包
    • 将字节码(.class)进行分类存放
    • 包其实就是文件夹
  • 包的概述
    • 举例:
      • 需求:
        • 学生:增加、删除、修改、查询
        • 老师:增加、删除、修改、查询
      • 方案1:按照功能分
        • com.heima.add
          • AddStudent
          • AddTeacher
        • com.heima.delete
          • DeleteStudent
          • DeleteTeacher
        • com.heima.update
          • UpdateStudent
          • UpdateTeacher
        • com.heima.find
          • FindStudent
          • FindTeacher
      • 方案2:按照模块分
        • com.heima.teacher
          • AddTeacher
          • DeleteTeacher
          • UpdateTeacher
          • FindTeacher
        • com.heima.student
          • AddStudent
          • DeleteStudent
          • UpdateStudent
          • FindStudent
  • 包的定义
    • 格式
      • package 包名;
      • 多级包用“.” 分开即可
    • 注意事项
      • package语句必须是程序的第一条可执行的代码
      • package语句在一个java文件中只能有一个
      • 如果没有package,默认表示无包名
    • 案例演示
      • package com.heima;
        // package语句必须是程序的第一条可执行的代码
        // 一个文件内只能有一个package语句
        
        
        class Demo1_Package {
            public static void main(String[] args) {
                
            }
        }
  • 如何编译运行带包的类
    • 案例演示
      • javac编译时加上-d即可
        • javac -d . HelloWorld.java
      • 通过java命令执行
        • java 包名.HelloWorld
        • java com.heima.Demo1_Package
  • 不同包下类之间的访问
    • 案例演示
    • package com.heima;
      // package语句必须是程序的第一条可执行的代码
      // 一个文件内只能有一个package语句
      
      import com.baidu.Person;
      import com.xxx.Student;
      //import java.util.Scanner;        //在开发中我们用的都是导入具体的类
      import java.util.*;                //*代表通配符,他会到该包下挨个匹配,匹配上就导入
      class Demo1_Package {
          public static void main(String[] args) {
              Person p = new Person("张三",23);
              System.out.println(p.getName() + "..." + p.getAge());
              //p.print();            //在不同包下的无关类,不允许访问,因为是protected修饰的
      
              /*Scanner sc = new Scanner(System.in);
              int x = sc.nextInt();
              System.out.println(x);*/
              
              Student s = new Student("李四",24);
              System.out.println(s.getName() + "..." + s.getAge());
              s.method();
          }
      }
      View Code
  • import关键字的概述和使用 

    • 为什么要有import

      • 其实就是让有包的类对调用者可见,不用写全类名了

    • 导包格式

      • import 包名;

      • 注意:

        • 这种方式导入是到类的名称。

        • 虽然可以最后写*,但是不建议。

    • package,import,class有没有顺序关系
      • 有。
      • package 第一行,只能一个文件一句
      • import 中间,可以有多句
      • class 放在这两个下面

5. 修饰符

  • 四种权限修饰符
    • private 本类;
    • 默认     本类;同一个包下(子类和无关类)
    • protected  本类;同一个包下(子类和无关类);不同包下(子类)
    • public   本类;同一个包下(子类和无关类);不同包下(子类);不同包下(无关类)
  • 修饰符
    • 权限修饰符:private,默认的,protected,public
    • 状态修饰符:static,final
    • 抽象修饰符:abstract
    • 权限修饰符:默认修饰符,public
    • 状态修饰符:final
    • 抽象修饰符:abstract
    • 用的最多的就是:public
  • 成员变量:

    • 权限修饰符:private,默认的,protected,public

    • 状态修饰符:static,final

    • 用的最多的就是:private

  • 构造方法:

    • 权限修饰符:private,默认的,protected,public

    • 用的最多的就是:public

  • 成员方法:

    • 权限修饰符:private,默认的,protected,public

    • 状态修饰符:static,final

    • 抽象修饰符:abstract

    • 用的最多的就是:public

  • 除此以外的组合规则:

    • 成员变量:public static final

    • 成员方法:

      • public static

      • public abstract

      • public final

6. 内部类

  • 内部类概述

    • 在类中定义类,叫做内部类
  • 内部类访问特点

    • 内部类可以直接访问外部类的成员,包括私有。

    • 外部类要访问内部类的成员,必须创建对象。

    • 外部类名.内部类名 对象名 = 外部类对象.内部类对象;

  • 案例演示

    • class Demo1_InnerClass {
          public static void main(String[] args) {
              //Inner i = new Inner();
              //i.method();
              //外部类名.内部类名 = 外部类对象.内部类对象
              Outer.Inner oi = new Outer().new Inner();            //创建内部类对象
              oi.method();
      
          }
      }
      
      
      
      class Outer { // 外部类
          private int num = 10;
      
          class Inner {  // 内部类
              public void method() {
                  System.out.println(num);
              }
          }
      }
  • 内部类分类
    • 成员内部类
      • 成员内部类私有使用
        • class Demo2_InnerClass {
              public static void main(String[] args) {
                  //Outer.Inner oi = new Outer().new Inner(); //内部类私有,无法调用
                  //oi.method();
          
                  Outer o = new Outer();
                  o.print();
              }
          }
          
          class Outer {
              private int num = 10;
              
              private class Inner { //内部类私有
                  public void method() {
                      System.out.println(num);
                  }
              }
          
              public void print() {
                  Inner i = new Inner();  // 外部类,提供内部类实例化方法
                  i.method();
              }
          }
          内部类私有
        • class Test1_InnerClass {
              public static void main(String[] args) {
                  Outer.Inner oi = new Outer().new Inner();
                  oi.show();
              }
          }
          //要求:使用已知的变量,在控制台输出30,20,10。
          //内部类之所以能获取到外部类的成员,是因为他能获取到外部类的引用外部类名.this
          class Outer {
              public int num = 10;
              
              class Inner {
                  public int num = 20;
                  public void show() {
                      int num = 30;
                      System.out.println(num);
                      System.out.println(this.num);
                      System.out.println(Outer.this.num);
                  }
              }
          }
          成员内部类面试题:获取成员变量
    • 静态成员内部类
      • class Demo1_InnerClass {
            public static void main(String[] args) {
                //外部类名.内部类名 对象名 = 外部类名.内部类对象;
                Outer.Inner oi = new Outer.Inner();
                oi.method();
        
                Outer.Inner2.print();
            }
        }
        
        class Outer {
            
            static class Inner { // 静态成员内部类
                public void method() {
                    System.out.println("method");
                }
            }
        
            static class Inner2 {
                public static void print() {
                    System.out.println("print");
                }
            }
        }
        静态内部类
    • 局部内部类
      • 局部内部类,只能在其所在的方法中访问
      • 局部内部类访问局部变量的问题
        • 局部内部类访问局部变量必须用final修饰
        • 局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么?

          • 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失。

          • 那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了。

          • 如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用。

          • 但是jdk1.8取消了这个事情,所以我认为这是个bug

        • class Demo1_InnerClass {
              public static void main(String[] args) {
                  Outer o = new Outer();
                  o.method();
              }
          }
          //局部内部类
          class Outer {
          
              public void method() {
                  final int num = 10;
                  //int num = 10; 错误:从内部类中访问本地变量num;需要被声明为最终类型。final
          
                  class Inner {   // 局部内部类
                      public void print() {
                          System.out.println(num);
                      }
                  }
          
                  Inner i = new Inner(); //只能在局部所在的方法中访问
                  i.print();
              }
          
              /*public void run() {
                  Inner i = new Inner();        //局部内部类,只能在其所在的方法中访问
                  i.print();
              }*/
          }
          局部内部类示例,final修饰符修饰变量
    • 匿名内部类
      • 就是内部类的简化写法。
      • 前提:
        • 存在一个类或者接口
        • 这里的类可以是具体类也可以是抽象类。
      • 格式
        • new 类名或者接口名() {
              重写方法;
          }

      • 本质是什么呢?
        • 是一个继承了该类或者实现了该接口的子类匿名对象。
      • 案例演示
        • class Demo1_NoNameInnerClass {
              public static void main(String[] args) {
                  Outer o = new Outer();
                  o.method();
              }
          }
          
          
          interface Inter {
              public void print();
          }
          
          class Outer {
          
              /*class Inner implements Inter {  // 这是有名字的内部类,继承Inter接口
                  public void print() {
                      System.out.println("print");
                  }
              }*/
          
              public void method(){
                  //Inner i = new Inner();
                  //i.print();
                  //new Inner().print();
                  //Inter i = new Inner();            //父类引用指向子类对象
                  
                  new Inter() {                        //实现Inter接口
                      public void print() {            //重写抽象方法
                          System.out.println("print");
                      }
                  }.print();     //
              }
          }
          匿名内部类:单个方法调用
        • class Demo2_NoNameInnerClass {
              public static void main(String[] args) {
                  Outer o = new Outer();
                  o.method();
              }
          }
          
          interface Inter {
              public void show1();
              public void show2();
          }
          //匿名内部类只针对重写一个方法时候使用
          class Outer {
              public void method() {
                  /*new Inter(){
                      public void show1() {
                          System.out.println("show1");
                      }
          
                      public void show2() {
                          System.out.println("show2");
                      }
                  }.show1();
          
                  new Inter(){
                      public void show1() {
                          System.out.println("show1");
                      }
          
                      public void show2() {
                          System.out.println("show2");
                      }
                  }.show2();*/
          
                  Inter i = new Inter(){
                      public void show1() {
                          System.out.println("show1");
                      }
          
                      public void show2() {
                          System.out.println("show2");
                      }
          
                      /*public void show3() {
                          System.out.println("show3");
                      }*/
                  };
          
                  i.show1();
                  i.show2();
                  //i.show3();  //匿名内部类是不能向下转型的,因为没有子类类名
              }
          }
          匿名内部类只针对重写一个方法时候使用
      • 匿名内部类在开发中的应用
        • class Test1_NoNameInnerClass {
              public static void main(String[] args) {
                  //如何调用PersonDemo中的method方法呢?
                  PersonDemo pd = new PersonDemo ();
                  //pd.method(new Student());
                  pd.method(new Person() {
                      public void show() {
                          System.out.println("show");
                      }
                  });
              }
          }
          //这里写抽象类,接口都行
          abstract class Person {
              public abstract void show();
          }
          
          class PersonDemo {
              
              //public void method(Person p) {        //Person p = new Student();        //父类引用指向子类对象
              /*
              Person p = new Person(){
                  public void show() {
                      System.out.println("show");
                  }
              };
              */
              public void method(Person p) {
                  p.show();
              }
          }
          
          class Student extends Person {
              public void show() {
                  System.out.println("show");
              }
          }
          匿名内部类在开发中,当做参数传递(把匿名内部类当做一个对象)
        • class Test2_NoNameInnerClass {
              public static void main(String[] args) {
                  //Outer.method().show();            //链式编程,每次调用方法后还能继续调用方法,证明调用方法返回的是对象
                  Inter i = Outer.method();
                  i.show();
              }
          }
          //按照要求,补齐代码
          interface Inter { 
              void show(); 
          }
          
          class Outer { 
              //补齐代码 
              public static Inter method() {
                  return new Inter() {
                      public void show() {
                          System.out.println("HelloWorld");
                      }
                  };
              }
          }
          
          //要求在控制台输出”HelloWorld”
          根据主方法的调用方法,补齐代码
原文地址:https://www.cnblogs.com/zoe233/p/12759781.html