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("飞出去救人");
      }
      }

超人作为人类身份的属性信息对外展示,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("看家");
        }
        }

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("猫吃鱼");
        } }
      • 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() }
    • 抽象类联系(猫狗,抽象类为动物)
      • 具体事物:猫,狗
        共性:姓名,年龄,吃饭
        猫的特性:抓老鼠
        狗的特性:看家

      • 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("抓老鼠");
        }
        }
      • 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
        }

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() {}
        }
      • 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");
      }
      }
  • 接口与接口
    • 继承关系

      • 可以单继承,也可以多继承。
      • 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 {
        }

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();
      }
      }
  • 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”

          根据主方法的调用方法,补齐代码

【JAVA基础】08 面向对象3的更多相关文章

  1. Java基础-初识面向对象编程(Object-Oriented-Programming)

    Java基础-初识面向对象编程(Object-Oriented-Programming) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Java是一门面向对象的程序设计语言.那么什 ...

  2. 黑马程序员——【Java基础】——面向对象(二)异常机制、包(Package)

    ---------- android培训.java培训.期待与您交流! ---------- 一.异常机制 (一)异常概述 1.异常:就是程序在运行时出现不正常情况. 2.异常类:程序在运行时,出现的 ...

  3. Java基础之面向对象以及其他概念

    一.基础知识:1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java语言是跨平台,jvm不是跨平台的. JR ...

  4. Java基础08 继承

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 继承(inheritance)是面向对象的重要概念.继承是除组合(composit ...

  5. Java基础08 继承(转载)

    继承(inheritance)是面向对象的重要概念.继承是除组合(composition)之外,提高代码重复可用性(reusibility)的另一种重要方式.组合是重复调用对象的功能接口.继承可以重复 ...

  6. 【Java基础】面向对象下

    面向对象下 这一章主要涉及其他关键字,包括 this.super.static.final.abstract.interface.package.import 等. static 在 Java 类中, ...

  7. 【java基础】面向对象的三大基本特征之-------继承

    面向对象的三大特征:封装,继承,多态 java通过extends关键字来实现继承,而且是单继承,一个子类只可以有一个直接父类,但是父类还可以有父类... java.long.Object是所有类的父类 ...

  8. 黑马程序员——【Java基础】——面向对象(一)概述、类与对象、继承、抽象类、接口、多态、内部类

    ---------- android培训.java培训.期待与您交流! ---------- 一.面向对象概述 1.面向对象:是一个很抽象的概念,它相对面向过程而言,是一种程序设计的思想. 2.面向对 ...

  9. Python基础08 面向对象的基本概念

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 谢谢逆水寒龙,topmad和Liqing纠错 Python使用类(class)和对 ...

  10. 再探java基础——对面向对象的理解(1)

    对象 对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则.计划或事件.对象具有属性和行为,在程序设计中对象实现了数据和操作的结合,使数 ...

随机推荐

  1. 监控一哥Prometheus你可认识?

    先大致认识认识普罗米修斯 —— Prometheus. 依据官方文档https://prometheus.io/docs/introduction/overview/ 大概能够了解到 Promethe ...

  2. stylus--安装及使用方法

    stylus介绍 Stylus 是一个CSS的预处理框架,2010年产生,来自Node.js社区,主要用来给Node项目进行CSS预处理支持,所以 Stylus 是一种新型语言,可以创建健壮的.动态的 ...

  3. 安装 elasticsearch For LINUX

    官网下载地址 https://www.elastic.co/cn/downloads/elasticsearch 选择版本为LINUX 当前版本为 es-7.6.2 用tar 命令解压 tar -zx ...

  4. 部署MYSQL高可用集群

                                                  mysql-day08     部署MYSQL高可用集群 u 集群架构                   ...

  5. Go gRPC教程-服务端流式RPC(三)

    前言 上一篇介绍了简单模式RPC,当数据量大或者需要不断传输数据时候,我们应该使用流式RPC,它允许我们边处理边传输数据.本篇先介绍服务端流式RPC. 服务端流式RPC:客户端发送请求到服务器,拿到一 ...

  6. python10

     一.多进程multiprocessing multiprocessing包是Python中的多进程管理包.与threading.Thread类似,它可以利用multiprocessing.Proce ...

  7. hadoop(五)scp命令copy文件和配置(完全分布式准备二)|7

    机器的克隆参考centos7克隆ip|机器名|映射关系|别名配置(hadoop完全分布式准备一) 那么问题来了,如果我们有30台机器,之间可以互相访问,那我们如何快速安装配置环境如jdk hadoop ...

  8. Flex Socket与Java通信实例说明(转)

    Flex Socket与Java通信实例说明(转) 这两天一直在flex的Socket ,现在终于懂了很多.由浅到深一步一步深入.慢慢体会实例,虽然实例都是在网上找的,但也经过了我的测试.我比较喜欢注 ...

  9. 运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接

    运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接 最近在项目中可能要用到socket相关的东西来发送消息,所以初步研究了下socket的TC ...

  10. fork()系统调用的理解

    系统调用fork()用于创建一个新进程.我们可以通过下面的代码来理解,最好是能自己敲一遍运行验证. ​#include<stdio.h> #include<stdlib.h> ...