JAVA学习笔记——第十章 面向对象高级

🔥博客主页: A_SHOWY
🎥系列专栏力扣刷题总结录 数据结构  云计算  数字图像处理  力扣每日一题_

一、类变量和类方法

1.1 引出类变量

 类变量的快速入门:类变量被所有对象实例共享

package com.hspedu.static_;

public class ChildGame {
    public static void main(String[] args) {
        Child child1 = new Child("白骨精");
        child1.join();
        child1.count++;

        Child child2 = new Child("白骨精");
        child2.join();
        child2.count++;

        Child child3 = new Child("白骨精");
        child3.join();
        child3.count++;
        //类变量可以通过类名来访问
        System.out.println("共有" + Child.count +"小孩加入了游戏");
    }
}

class Child{
    private String name;
    //定义一个变量child,是一个类变量(静态变量)

    //该变量最大的特点是会被Child类的所有对象实例共享
    public static int count  = 0;
    public Child(String name) {
        this.name = name;
    }
    public void join(){
        System.out.println(name + "加入了游戏..");
    }
}

 1.2 类变量内存布局

 两种说法,有一点是肯定的,静态变量是被对象共享的,一种说法是在堆里,另一种说法是在静态域(jdk8以前)里面。

两点共识:

  1. static变量被同一个类的所有对象共享
  2. static类变量,在类加载的时候就生成

1.3 类变量定义 

类变量也叫静态变量/静态属性,是该类所有对象共享的变量 

1.4 如何定义类变量

访问修饰符 static 数据类型 变量名;//常用
static 访问修饰符 数据类型 变量名;

1.5 如何访问类变量

1. 类名.类变量名      // 推荐
2. 对象名.类变量名    //静态变量的访问修饰符的访问权限和范围和普通的属性是一样的
package com.hspedu.static_;

public class VisitStatic {
        public static void main(String[] args) {
            //类变量随着类的加载创建的,即使没有创建对象实例也可以访问,当然通过对象实例也能访问
            System.out.println(A.name);
            A a = new A();
            System.out.println(a.name);
        }
}
class A{
    //类变量
    public static String name = "cpy";

}

如果static前面变成private,那么另一个就不能访问他了,遵循基础规则

*1.6 类变量使用细节 

 

1.7 类方法基本介绍 

形式:只需要普通方法前面加一个static        

调用:类名.类方法名或者对象名.类方法名   (满足访问修饰符的权限)

小例子:总学费

package com.hspedu.static_;

public class StaticMethod {
    public static void main(String[] args) {
        Stu tom = new Stu("tom");
        tom.payFee(100);
        Stu mary = new Stu("mary");
        mary.payFee(200);
        Stu.showFee();
    }
}
 class  Stu{
    private String name;
    //定义一个类变量累计学生的学费
    static private double fee = 0;

     public Stu(String name) {
         this.name = name;
     }
     //static:静态方法,静态方法只能访问静态属性
     static public void payFee(double fee){
         Stu.fee += fee;//累计
     }
     static public void showFee(){
         System.out.println("总学费有" + Stu.fee);
     }
 }

 1.8 类方法经典使用场景

如果我们不创建实例,也可以掉某个方法,及当作工具来使用! ,这时把方法做成静态方法合适

 *1.9 类方法使用细节

 4)注释:不能用是因为类变量和类方法随着类的加载而加载,类的加载比对象的创建要早,如果使用this或者super的话,会找不到这个对象5)静态方法只能访问静态成员

 1.10 课堂练习

(1)答案:9,10,11

(2)答案:

1.id++那里错的,类方法中只能访问静态变量和静态方法

2.输出是0和1,注意构造器这里不能是static所以这里没错

(3)答案: 

1.在静态方法中不能使用this

2.total的值最后等于4

总结:

  1. 静态方法只能访问静态成员
  2. 非静态方法可以访问所有成员
  3. 编写代码时候仍要遵守访问权限规则 

1.11 main方法 

注释:

1.一定记住:main方法由虚拟机调用

2.把public去了就直接不能执行了

5.问:你这个字符串数组【String【】 args】形参从哪里传进去的:是在执行这个程序的时候,在后边传进去的参数形成的数组        

 

这就是为什么我们每次访问非静态成员,都要创建个对象 !         

package com.hspedu.static_;

public class Main01 {

    private static String name;
    private int age;
    private static void sayhi(){
        System.out.println("hi");
    }
    public static void main(String[] args) {
        //可以直接使用name
        //1.静态方法main可以访问本类的静态成员
        System.out.println(name);
        sayhi();
        //2.静态方法main不可以访问本来的非静态成员
        //age;
        //包括方法
        //3.静态方法main要访问本类的静态成员要创建对象先
        Main01 main01 = new Main01();
        System.out.println(main01.age);
    }
}

 1.12 补充:在idea中传递参数给java程序

package com.hspedu.static_;

public class Main02 {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}

 

二、代码块 

 2.1 基本介绍

2.2 基本语法

 2.3 快速入门

代码块的调用要优先于构造器,就比如构造器重载的时候,三个构造器,第一个构造器是一个参数,第二个是两个参数,第三个是三个参数,但是他们的内容都是一样的,这样就不如搞一个代码块放在最前面

2.4 代码块细节

  1.  代码块前面加一个staitc表示静态代码块,作用就是对类进行初始化,随着类的加载而执行,只会执行一次。如果是普通代码块,每次创建一个对象就执行,每创建一次就执行一次
  2. (重要)类什么时候被加载:1)当创建对象实例的时候(new)2)创建子类对象实例的时候,父类也会被加载 (比如说父类中有一个代码块,子类中也有一个,然后创建一个子类对象,他就会先加载一个父类的代码块再加载一个子类代码块)  3)使用类的静态成员时(这个类中的代码块会被加载) 
  3. 注意,如果只使用类的静态成员,普通代码块并不会执行!!!,因为类加载和这个普通代码块没有关系,普通代码块是构造器的补充,普通代码块调用了,他就被调用了
    package com.hspedu.static_;
    
    public class CodeBlockDetail01 {
        public static void main(String[] args) {
            System.out.println(DD.n1);
        }
    }
    class  DD{
        public static int n1 = 8888;
        //静态代码块
        static{
            System.out.println("DD的静态代码块被执行");
        }
        {
            System.out.println("DD的普通代码块被执行");
        }
    }

  4. (重点+难点) 创建对象的时候,在一个类中的调用顺序
    //1.静态代码块和静态属性初始化,谁在前面谁先
    package com.hspedu.static_;
    
    public class Stati从Method2 {
        public static void main(String[] args) {
            AA aa = new AA();
        }
    }
    class AA{
        static {
            System.out.println("静态代码块被调用");
        }
        //静态属性初始化
        private static int a = getN1();
        private static int getN1(){
            System.out.println("getN1被调用");
            return 100;
        }
    }
  5. 构造器的最前面其实隐藏了super和调用普通代码块
  6. (综合带继承)顺序总结:先把静态的走完,剩下的从父类开始各走各的
  7. 静态代码块只能调用静态成员,普通代码块能调用所有代码块

在new的时候首先要进行类的加载,再进行创建对象 所以类的加载和静态相关的部分全部执行。设计到创建对象的时候就从父类开始了,因为子类隐藏了super()和普通代码块和普通属性的初始化等。参考5,其实综合起来核心就是

 2.5 代码块相关题目

题目一:答案:in static block ,total = 100,total = 100(因为类加载以后静态代码块就不再执行了)

题目二(重点题目):答案:

静态成员sam初始化,static块执行,|(该普通成员了),Sam1成员初始化 ,|(该构造器了)Test默认构造函数被调用

三、单例设计模式 

 3.1 什么是单例模式

单例:就是单个的实例,大概意思是指该类只能有一个对象实例 

3.1.1 饿汉式

(因为是私有的,在类内创建,所以在还没有使用到的时候就已经创建好了, 饿汉式可能造成创建了对象没有使用就造成了浪费

 注:私有化的目的是防止直接new一个对象 

这里有个很奇妙的点,就是为什么创建的对象和这个提供的公共方法都必须是static因为首先如果方法不是static那么需要先创建类才能调用,但是这个是个私有的,没法创建类,所以必须是static,而静态方法只能用静态成员,所以内部创建的对象也必须static ,形成了完美闭环,非常的神奇。

package com.hspedu.static_;

public class SingleTon {
    public static void main(String[] args) {
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);
        GirlFriend instance1 = GirlFriend.getInstance();
        System.out.println(instance1);
        System.out.println(instance1 == instance);
    }
}

class GirlFriend{
    private String name;

    //1.将构造器私有化
    //2.在类的内部直接创建对象(该对象是static的)
    //3.提供一个公共的static方法,返回gf对象

    private static GirlFriend gf = new GirlFriend("小国子");//只要类加载就创建对象
    private GirlFriend(String name) {
        this.name = name;
    }
    public  static GirlFriend getInstance() {
         return gf;
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

3.1.2 懒汉式

单例模式的对象通常是重量级的对象,如果你创建了没有用就浪费了。饿汉式可能造成创建了对象但是没有使用的弊端。

package com.hspedu.static_;

public class SingleTon2 {
    public static void main(String[] args) {
        System.out.println(Cat.n1);//这样的话不会创建对象,只进行类加载
        Cat instance = Cat.getInstance();
         System.out.println(instance);
         Cat instance2 = Cat.getInstance();
         System.out.println(instance2);
        System.out.println(instance2 == instance);

    }
}
class Cat{
    public static int n1 = 100;
    private String name;
    private static Cat cat;
    //1.仍然私有化构造器
    //2.定义一个私有的静态属性的对象
    //3.提供一个公共的static方法,可以返回Cat对象
    private Cat(String name) {
        this.name = name;
    }
    public static Cat getInstance() {
        if(cat == null) {
            cat = new Cat("小cat");
        }
        return cat;
    }
}

代码中判断是否为空的目的,是假如说他再次创建对象肯定就不是空的了,这时候就不需要再重新创建一个对象,直接返回原有Cat对象即可,保存的单例模式的特征。 

四、final关键字 

4.1 基本介绍

4.2 细节

关于final修饰的静态属性初始化位置: 可以这样理解:因为是static和final,那么在类加载的时候就要创建好相应的属性,所以在构造器的时候修改,就违反了final不可修改的规定 。同时static在类加载的时候就要给值,它等不到你构造器创建对象!

 注释5:它都不能被继承了,都没有重写的必要了,一般我们重写都是继承了以后,想要特殊功能

注释7:从下列代码和结果可以看到直接使用类的静态成员导致类加载,但是final能抑制这个类加载,所以不会输出静态代码块! 

package com.hspedu.static_;

public class SingleTon2 {
    public static void main(String[] args) {
        System.out.println(BBB.num);
    }
}
class BBB{
    public  final static int num = 100000;
    static {
        System.out.println("BBB静态代码块被执行");
    }
}

 

4.3 练习

4.3.1 练习1

//1.在定义的时候赋值
class Circle{
    private double radius;
    private final double PI = 3.14;

    public Circle(double radius) {
        this.radius = radius;
    }
}
//2.在构造器的时候赋值
class Circle{
    private double radius;
    private final double PI;

    public Circle(double radius) {
        this.radius = radius;
        PI = 3.14;
    }
}
//3.在代码块中赋值
class Circle{
    private double radius;
    private final double PI;

    public Circle(double radius) {
        this.radius = radius;
    }
    {
        PI = 3.14;
    }

   public double calArea() {
        return PI * radius * radius;
    }
}
}

4.3.2 练习2 

错误,++x修改了final修饰的值,但是形参加上final是对的 

五、抽象类

 5.1 抽象类的引出

父类方法的不确定性:当父类的某些方法需要声明,但是又不确定如何实现的时候,可以将其声明为抽象方法,那么这个类就是抽象类 ,一般来说抽象类会被继承,由其子类来实现

  5.2 抽象类的细节

  1. 抽象类不能被实例化
  2. 抽象类可以没有抽象方法 
  3. 一旦包含了抽象方法,那么这个类必须声明为抽象类
  4. abstract只能修饰类和方法,但是不能修饰属性和其他的
  5. 抽象类的本质还是类,所以类内部还是可以拥有任何可以拥有的方法
  6. 抽象类不能有主体,即不能实现
  7. 如果一个类继承了抽象类,它必须实现抽象类的所有方法,除非他自己也声明了抽象类//只要有方法体{}就称为实现了
  8. 抽象方法不能使用private ,final,static修饰,因为这些关键字和重写都是冲突的,private和final好理解,static的话:static修饰的方法是静态方法,其可以直接被类调用。而abstract是修饰的方法是抽象方法,即无代码体的方法,不能被直接调用,需要子类或者实现类去编写完整的方法处理逻辑了才能使用。

5.3 抽象类练习          

1)错误,因为final不能被继承,所以你这里抽象了,后边没法实现

2)错误static关键字和方法重写无关,具体看上面的第八条。

3)不行,因为私有的别人不能重写

4)太简单了不写了

5.4 抽象类最佳实践——模板设计模式 

 思路1:最容易想到的

 发现代码冗余,他们都有公共的代码部分,就是计算开始和结束时间,我们可以分别把这个抽出来,然后去改job但是还是很麻烦

package com.hspedu.static_;

public class AABB {
    //计算任务
    //1..10000
    public void job(){
        //得到开始的时间
        long start = System.currentTimeMillis();
        int num = 0;
        for (int i = 1; i <= 100000000; i++) {
            num +=  i;
        }
        //得到结束的时间
        long end  = System.currentTimeMillis();
        System.out.println("执行的时间是" + (end - start));
    }
}
package com.hspedu.static_;

public class BB {
    public void job(){
        //得到开始的时间
        long start = System.currentTimeMillis();
        int num = 0;
        for (int i = 1; i <= 800000; i++) {
            num *=  i;
        }
        //得到结束的时间
        long end  = System.currentTimeMillis();
        System.out.println("执行的时间是" + (end - start));
    }
}

思路2:抽象模板类(抽象类+动态绑定机制)

其实核心思想就是普通方法嵌套抽象方法,这样子只需要改抽象方法就行了

package com.hspedu.static_;

abstract public class Template {
    public abstract void job();//抽象方法
    public void calculateTime(){
        long startTime = System.currentTimeMillis();
        job();//动态绑定机制,子类没有起找父类,然后执行方法看编译类型
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}


package com.hspedu.static_;

public class AABB extends Template{
    //计算任务
    //1..10000
    public void job(){
        //得到开始的时间
        long start = System.currentTimeMillis();
        int num = 0;
        for (int i = 1; i <= 100000000; i++) {
            num +=  i;
        }
    }
}


package com.hspedu.static_;

public class BB extends Template {
    public void job(){
        int num = 0;
        for (int i = 1; i <= 800000; i++) {
            num *=  i;
        }
    }
}


package com.hspedu.static_;

public class Test {
    public static void main(String[] args) {
        AABB aabb = new AABB();
        aabb.calculateTime();
        BB bb = new BB();
        bb.calculateTime();
    }
}

六、接口

6.1 快速入门

//USb接口
package com.hspedu.interface_;

public interface Usb {
    //规定的接口的相关方法,接口中的方法都是public 和abstract的,在接口中都是默认的,所以不用加abstract
    public void start();
    public void stop();

}

//phone
package com.hspedu.interface_;
//Phone类实现Usb接口,也就是Phone类需要实现usbInterface接口声明的方法
public class phone implements Usb{
    @Override
    public void start() {
        System.out.println("手机开始工作");
    }

    @Override
    public void stop() {
        System.out.println("手机停止了工作");
    }
}

//camera
package com.hspedu.interface_;

public class camera implements Usb{
    //实现接口,本质上就是把接口的方法完成
    @Override
    public void start() {
        System.out.println("相机开始工作了");
    }

    @Override
    public void stop() {
        System.out.println("相机停止了工作");
    }
}


//computer
package com.hspedu.interface_;
public class computer {
    //编写一个方法,计算机工作
    public void work(Usb usb){
        //通过接口使用方法
        usb.start();
        usb.stop();
    }
}


//Interface类
package com.hspedu.interface_;

public class Interface01 {
    public static void main(String[] args) {
    //创建手机,创建对象
        camera camera = new camera();
        phone phone = new phone();
        //创建计算机
        computer computer = new computer();
        computer.work(phone);//把手机接入到计算机
        System.out.println("===========");
        computer.work(camera);//把相机接入到计算机
    }
}

 这里在computer类中其实在形参部分有一个向上转型的思想,父类的引用指向子类的对象

6.2 基本介绍

 demo:

//Ainter接口
package com.hspedu.interface_;

public interface AInter {
    //写属性
    public int n1 = 19;
    //写方法
    public  void hi();//在接口中,抽象方法可以省略abstract关键字
    //在jdk8后可以有默认实现方法,需要加default!
    default public void ok(){
        System.out.println("ok");
    }
    //在jdk8后可以加静态方法
    public static void cry(){
        System.out.println("cry...");
    }
}

//interface02类
package com.hspedu.interface_;

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

    }
}


//如果一个类 implements实现接口,需要将接口的所有抽象方法全部都实现
class A implements AInter{
    @Override
    public void hi() {
        System.out.println("hi");
    }
}

如果一个类 implements实现接口,需要将接口的所有抽象方法全部都实现 !

6.3 应用场景

核心就是统一管理

这里其实又用到了向上转型,这里用个static就是为了不创建对象了简单测试一下 

6.4 注意事项和使用细节 

 1.接口不能实例化,接口的作用是让别的类去实现它,再用实现它的类去实例化

2.接口中所有的方法是public方法,接口抽象方法中可以不用 abstract修饰

3.一个普通类实现接口就必须把该接口的所有接口都实现,可以使用alt+enter解决

4.抽象类实现接口,可以不用实现接口的方法

5.一个类可以同时实现多个接口 

interface  IB{
    void show();
}
interface  IC{
    void hi();
}

class pig implements IB,IC{
    @Override
    public void show() {
    }
    @Override
    public void hi() {

    }
}

6.接口中的属性,其实都是public static final 的,比如int a  = 1;其实就是public static final int a = 1;(必须初始化)

7.接口中属性的访问形式:接口名.属性名

8.一个接口不能继承其他的,但是能继承多个其他接口

9.接口的修饰符只能是public和默认 

6.5 接口练习

这三个都完全正确,static属性可以被直接使用,在这里有点像继承,这里要注意当final修饰类的时候才说明不能被继承

6.6 接口和继承类的比较

简单理解:实现机制对我们单继承机制的补充 ,就比如小猴子继承了老猴子的东西,但是想学飞行或者游泳需要实现小鸟的飞行和小鱼的游泳

6.7 接口的多态特性

 1.其实就是向上转型:父类的引用指向子类的对象

2. 多态数组

用到了判断运行类型instanceof + 向下转型去调用特有方法

package com.hspedu.interface_;

public class interfacePoly {
    public static void main(String[] args) {
        Usb1[] usbs = new Usb1[2];
        usbs[0] = new Phone();
        usbs[1] = new Camera();
        for (int i = 0; i < usbs.length; i++) {
            usbs[i].work();//动态绑定,和运行类型绑定
            if(usbs[i] instanceof Phone){
                ((Phone) usbs[i]).call();//向下转型
            }
        }
    }
}


interface Usb1{
    void work();
}
class Phone implements Usb1{
    @Override
    public void work() {
        System.out.println("手机工作中");
    }

    public void call(){
        System.out.println("手机可以打电话");
    }
}
class  Camera implements Usb1{
    @Override
    public void work() {
        System.out.println("相机工作中");
    }
}

3.接口存在多态传递的现象

6.8 接口课堂练习 

第一句话接口里面的等价于 public static final int x = 0;

pX函数父类是B,接口是A,这个x不明确是谁,以下方式可以解决

总结:

七、内部类

7.1 基本介绍

补:类的五大成员

属性、方法、构造器、代码块、内部类 

7.2 内部类的分类

7.3 局部内部类

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名 

package com.hspedu;

public class localinnner {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m1();
    }
}
class Outer{//外部类
    private int n1 = 100;
    private void m2(){
        System.out.println("m2执行");
    }//私有方法
    public void m1(){//1.局部内部类常常定义在外部类的局部位置,方法内
        //3.不能添加访问修饰符,但是可以用final修饰
         final class  Inner{//局部内部类本质还是类
             private int n1 = 800;//和外部的n1重名了,遵守就近原则
             public void m1(){
                //5.局部内部类可以直接访问外部类的成员,比如下面,直接访问了外部类的n1和m2
                m2();
                System.out.println("n1=" + n1);//2.可以直接访问外部类的所有成员,包括私有的,输出800
                 System.out.println("外部类的n1" + Outer.this.n1);//想访问外部类的n1的话用类名 + this.属性名
                 //OUter.this的本质是外部类的对象,即谁调用了m1代码,这个Outer.this就指向哪个对象 
            }
        }
//        class Inner2 extends Inner{
//        }

        //6.外部类在方法中,可以创建Inner对象,然后调用方法,必须在作用域中
        Inner inner = new Inner();
         inner.m1();
    }
    //4.作用域:仅仅在定义它的方法或者代码块中
    // 代码块中写内部类
    {
        class Inner03{}
    }

}

7.4 匿名内部类(最重要)

说明:匿名内部类是定义在外部类的局部位置,比如方法中并且没有类名

1) 本质是类 2)内部类 3)该类没有名字 4)同时还是一个对象

我的理解是就是这个匿名内部类起到一个简化作用,在做一个基于接口或者基于别的类的时候,只想用一次,每次调用接口都要创建一个新的类,那你创建一个匿名内部类省略了创建类的步骤 ,简化开发。这个匿名内部类用一次就没有了,你再new就不行了就是这个Outer04,但是返回的实例那个对象可以反复使用

demo1基于接口的匿名内部类

public class Anonymous {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}
class Outer04{
    private int n1 = 10;
    public void method(){
//        A tiger = new Tiger();
//        tiger.cry();
        //基于接口的匿名内部类
        //1.需求:想使用IA接口,并创建对象
        //2.传统方式,写一个类,实现该接口
        //3.这个Tiger这个类我可能只用一次就不用了,有点罗嗦,不同的动物叫都要写一个类
        //4.可以使用匿名内部类简化开发
        //5.tiger的编译类型?IA
        //6.tiger的运行类型?就是在这个匿名内部类  XXXX=>Outer04$1
        /*
        * 我们看底层,底层会分配一个类名
        * class XXXXX implements A{
             @override
             public void cry(){
             System.out.println("老虎在叫");
    }
        * */
        //7.jdk在底层创建匿名内部类Outer04$1,立即马上创建了一个实例,并把地址返回给tiger
        //8.匿名内部类使用一次就不能再使用了
        A tiger = new A(){//相当于是new了是实现A接口类的对象
            @Override
            public void cry() {
                System.out.println("老虎叫唤");
            }
        };
        System.out.println("tiger的运行类型" + tiger.getClass());
        tiger.cry();
    }
}

interface A{//接口
    public void cry();
}

//class Tiger implements A{
//    public void cry(){
//        System.out.println("老虎在叫");
//
//    }
//}

class Father{
    public Father(String name) {
    }
    public void test(){

    }
}

demo2基于类的匿名内部类

public class Anonymous {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}
class Outer04{
   
        //分析
        //1.father的编译类型 Father
        //2.father的运行类型Outer04&2
        //3.底层创建匿名内部类,由于Father类里面什么都没有,所以这里可以什么也没有,如果是抽象类,那里面的方法必须要实现
        //个人理解:学到这里匿名内部类其实就是实例化对象,同时重写一些类的方法或者实现接口
        /*
             class Outer04&2 extends Father{

             }
        **/
        //4.同时也直接返回了匿名内部类Outer04&2的对象
        //5.注意这个地方的参数列表会传递给构造器,这里的jack其实可以理解为super后边的那个参数
        Father father = new Father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };

        father.test();//检查一下

        //基于抽象类的匿名内部类,抽象类的方法就必要要实现了
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("小狗吃骨头");
            }
        };
        animal.eat();

        System.out.println("father对象的运行类型" + father.getClass());//OUter04&2
    }
}
class Father{
    public Father(String name) {
        System.out.println("接收到了name");
    }
    public void test(){

    }
}

abstract class Animal{
     void eat(){

    }
}

7.5 匿名内部类实践(使用场景)

demo1 用作实参直接传递

package com.hspedu.interface_;

public class innerclassExercise
{
    public static void main(String[] args){
        //本质上是一个接口的匿名内部类
    f1(new IL() {
        @Override
        public void show() {
            System.out.println("调用了匿名内部类");
        }
    });
    //这是我自己写的
        IL demo8 = new IL(){
            @Override
            public void show() {
                System.out.println("调用了匿名内部类");
            }
        };
        demo8.show();
    }
    //静态方法,形参是接口类型
    public static void f1(IL il){
        il.show();
    }

}

//接口
interface IL{
    void show();
}

demo2  上一个demo的实例(自己能做出来牛逼)

package com.hspedu.interface_;

public class innerclaseeexercise2 {
    public static void main(String[] args) {
        Cellphone cell = new Cellphone();
        cell.alarmclock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });
        cell.alarmclock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}
interface Bell{
    void ring();
}

class  Cellphone{
    public void alarmclock(Bell bell){
        bell.ring();
    }
}

7.6 成员内部类

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰 

1.需要成员内部类定义在外部内的成员的位置上

2.可以添加任意的访问修饰符,因为他本身就是一个成员(public,protected等)

第六点比较重要,外部其他类去使用成员内部类,主要有两种方法

//第一种方式
//如何理解:把Outer08去掉以后就是一个正常的实例化,加上Outer08就是内部的一个类的实例化,相当于把inner08()当作outer08的成员,就是一个语法问题
OUter08.Inner08 inner08 = outer08.new Inner08();//就像访问成员一样
//第二种方式,在外部类中写一个方法,可以返回一个Inner08的对象
//该方法直接返回Inner08的实例
public Inner08 getInner08Instance(){
    return  new inner08();
}

Outer08.Inner08 inner08Instance = outer08.getInner08Instance();

7.如果外部类和内部类的成员重名了,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员可以使用外部类名.this.成员去访问,和前面那个局部内部类是一样的

7.7 静态内部类 

说明:静态内部类是定义在外部类的成员位置,并且有static修饰

package com.hspedu.interface_;

public class memberinnnerClass {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.m1();
        //8.外部其他类去访问静态内部类
        //第一种方法,静态内部类可以通过类名直接访问的(满足访问权限)Outer10.Inner10.var()
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //第二钟方式,编写一个可以返回静态内部类的静态实例
        Outer10.Inner10 inner101 = outer10.getInner10();
        inner101.say();
        //第三种方式,这里直接不用创建对象了
        Outer10.getInner10_().say();
    }
}
class Outer10{//外部类
        private int n1 = 10;
        private static String name = "张三";
        private static  void crt(){

        }
        //Inner10就是一个静态内部类
    //1.放在外部类的成员位置
    //2.使用了static修饰
       public static class Inner10{
            //9.名字重复就近原则
            private static String name = "py";
            public void say(){
//                System.out.println(n1);这里是报错的,因为静态类只能访问静态成员
                //3.可以访问外部类的所有静态成员,但不能访问非静态成员
                //4.可以添加任意访问修饰符,因为他的地位就是一个成员
                System.out.println(name);
                //9.想访问外部类name,这里不需要加this,因为静态成员不需要类名.属性名调用,以前的this指的是类名
                System.out.println(Outer10.name);
                crt();
                //6.静态内部类访问外部类的成员可以直接访问所有的静态成员

            }
        }
    //5.作用域 :同其他成员为整个整体
    //7.外部类如果要访问内部类的静态成员,要先创建对象再访问,m1就是outer10的一个方法,去访问内部类的say方法
        public void m1(){
            Inner10 inner10 = new Inner10();
            inner10.say();
        }
    //把他想象成一个静态成员
        public Inner10 getInner10(){
            return new Inner10();
        }
    //可以加一个static,因为静态方法可以访问静态的,因为这个Inner10是静态的
    public static  Inner10 getInner10_(){
        return new Inner10();
    }
}


补:小总结

7.8 习题1 

判断输出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_SHOWY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值