当前位置: 首页 > java >正文

Java | 韩顺平 循序渐进学Java自用笔记---OOP高级

        


一、类变量和类方法 static

1、提出问题
        说:有一群小孩在玩堆雪人
,不时有新的小孩加入,请问如何知道现在共有多少人在玩?
        编写程序解决。

2、传统方法解决
        

3、类变量内存布局
       
与 jdk 版本有关系,记住:
        (1)static 变量是同一个类所有对象共享
        (2)static 类变量,在类加载的时候就生成了
        Java static变量保存在哪?_java 1.8后静态变量存放在哪里-CSDN博客
        https://www.zhihu.com/question/59174759/answer/163207831
        

4、什么是类变量
        类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。


5、如何定义类变量
        定义语法:
        访问修饰符 static 数据类型 变量名; [推荐]
        static 访问修饰符 数据类型 变量名;

6、如何访问类变量
        类名.类变量名
        或者 对象名.类变量名
        【静态变量的访问修饰符的访问权限和范围 和 普通属性是一样的。】
        推荐使用:类名.类变量名;
        说明:类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问

7、类变量使用注意事项和细节讨论
        什么时候需要用类变量?
        当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量);比如:定义学生类,统计所有学生共交多少钱。Student(name,static fee)
        类变量与实例变量(普通属性)区别类变量是该类的所有对象共享的,而实例变量是每个对象独享的,加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
        类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,但java设计者推荐我们使用 类名.类变量名方式访问。【前提是 满足访问修饰符的访问权限和范围】
        实例变量不能通过 类名.类变量名 方式访问,类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了就可以使用类变量了。
        类变量的生命周期是随类的加载开始,随着类消亡而销毁。

8、类方法基本介绍
        类方法也叫静态方法 。
        形式如下:访问修饰符 static 数据返回类型方法名(){}【推荐】
                           static 访问修饰符 数据返回类型 方法名(){}

9、类方法的调用
        使用方式: 类名.类方法名 或者 对象名.类方法名前提是 满足访问修饰符的访问权限和范围。

10、类方法使用场景
        当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
        比如:工具类中的方法 utilsMath类、Arrays类、Collections 集合类
        在程序员实际开发,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用了,比如打印一维数组,冒泡排序,完成某个计算任务 等..

11、类方法使用注意事项及细节
        
1)类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区。
        类方法中无this的参数
        普通方法中隐含着this的参数
        2)类方法可以通过类名调用,也可以通过对象名调用。
        3)普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
        4)类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
        5)类方法(静态方法)中 只能访问 静态变量 或静态方法。
        6)普通成员方法,既可以访问 非静态成员,也可以访问静态成员。
        小结: 静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员
(必须遵守访问权限)

        


 二、main方法

        main方法的形式:
        public static void main(String[] args){}
        1)main方法是虚拟机调用。
        2)java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public。不在同一类。
        3)iava虚拟机在执行main()方法时不必创建对象,所以该方法必须是static。
        4)该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
        5)java 执行的程序 参数1 参数2 参数3
        
        注意:
        在 main()方法中,我们可以直接调用 main 方法所在类的静态方法或静态属性。
        但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。
        在IDEA中传递参数:
        


三、代码块

1、基本介绍
        代码化块又称为初始化块,属于类中的成员[即 是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
        但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。 

2、基本语法
【修饰符】{
        代码
};
        注意:
        1)修饰符 可选,要写的话,也只能写 static。
        2)代码块分为两类,使用static 修饰的叫静态代码块,没有static修饰的叫普通代码块/非静态代码块。
        3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等。
        4);号可以写上,也可以省略。

3、代码块的好处和案例演示
        老师理解:
        1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
        2)场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用 

4、代码块使用注意事项和细节讨论
        1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。

        2)类什么时候被加载
        ① 创建对象实例时(new)
        ② 创建子类对象实例,父类也会被加载
        ③ 使用类的静态成员时(静态属性,静态方法)

        3)普通的代码块,在创建对象实例时,会被隐式的调用,被创建一次,就会调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。

        4)创建一个对象时,在一个类 调用顺序是:(重点,难点)
        ① 调用静态代码块和静态属性的初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
        ② 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
        ③ 调用构造方法。

        5)构造器 的最前面其实隐含了 super() 和 调用普通代码块。静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于 构造器和普通代码块执行的。
        class A {
                public A(){//构造器
                //这里有隐藏的执行要求
                //(1)super();//这个知识点,在前面讲解继承的时候,老师说过
                //(2)调用普通代码块的
                System.out.println("ok");
                }
        }

        6)创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
        ① 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
        ② 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
        ③ 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
        ④ 父类的构造方法
        ⑤ 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
        ⑥ 子类的构造方法

        7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。

        
        


 四、单例设计模式:静态方法和属性的经典使用

1、什么是设计模式
        设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。

2、什么是单例模式
        单例(单个的实例)
        所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
        单例模式有两种方式:1)饿汉式 2)懒汉式

3、单例模式应用
        演示饿汉式和懒汉式单例模式的实现。步骤如下:
        1)构造器私有化 =》 防止直接 new
        2)类的内部创建对象
        3)向外暴露一个静态的公共方法。

package com.hspedu.single_;
public class SingleTon01 {public static void main(String[] args) {// GirlFriend xh = new GirlFriend("小红");// GirlFriend xb = new GirlFriend("小白");//通过方法可以获取对象GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);GirlFriend instance2 = GirlFriend.getInstance();System.out.println(instance2);System.out.println(instance == instance2);//T//System.out.println(GirlFriend.n1);
//... }
}//有一个类, GirlFriend
//只能有一个女朋友
class GirlFriend {private String name;//public static int n1 = 100;//为了能够在静态方法中,返回 gf 对象,需要将其修饰为 static對象,//通常是重量級的對象, 餓漢式可能造成創建了對象,但是沒有使用. private static GirlFriend gf = new GirlFriend("小红红");//如何保障我们只能创建一个 GirlFriend 对象//步骤[单例模式-饿汉式]//1. 将构造器私有化//2. 在类的内部直接创建对象(该对象是 static)//3. 提供一个公共的 static 方法,返回 gf 对象private GirlFriend(String name) {System.out.println("構造器被調用.");this.name = name;}public static GirlFriend getInstance() {return gf;}@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}
}
package com.hspedu.single_;
/**
* 演示懶漢式的單例模式
*/
public class SingleTon02 {public static void main(String[] args) {//new Cat("大黃");//System.out.println(Cat.n1);Cat instance = Cat.getInstance();System.out.println(instance);//再次調用 getInstanceCat instance2 = Cat.getInstance();System.out.println(instance2);System.out.println(instance == instance2);//T}
}
//希望在程序運行過程中,只能創建一個 Cat 對象class Cat {private String name;public static int n1 = 999;private static Cat cat ; //默認是 null//步驟//1.仍然構造器私有化//2.定義一個 static 靜態屬性對象//3.提供一個 public 的 static 方法,可以返回一個 Cat 對象//4.懶漢式,只有當用戶使用 getInstance 時,才返回 cat 對象, 後面再次調用時,會返回上次創建的 cat 對象// 從而保證了單例private Cat(String name) {System.out.println("構造器調用...");this.name = name;}public static Cat getInstance() {if(cat == null) {//如果還沒有創建 cat 對象cat = new Cat("小可愛");}return cat;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +'}';}
}

4、饿汉式 VS 懒汉式
        二者最主要的区别在于创建对象的时机不同:
        饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
        饿汉式不存在线程安全问题,懒汉式存在线程安全问题。(后面学习线程后,会完善)
        饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
        在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式。


 五、final 关键字

1、基本介绍
        final 中文意思:最后的,最终的.final 可以修饰类、属性、方法和局部变量。
        在某些情况下,程序员可能有以下需求,就会使用到final:
        1)当不希望类被继承时,可以用final修饰。
        2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。
        访问修饰符 final 返回类型 方法名
        3)当不希望类的的某个属性的值被修改,可以用final修饰。
        public final double TAX RATE=0.08
        4)当不希望某个局部变量被修改,可以使用final修饰。
        final doubleTAX RATE=0.08

2、final 使用注意事项和细节讨论
        1)final修饰的属性又叫常量,一般 用 XX XX XX 来命名。
        2)final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】。
        ① 定义时:如 public final double TAX RATE=0.08;
        ② 在构造器中;
        ③ 在代码块中;
        3)如果final修饰的属性是静态的,则初始化的位置只能是① 定义时 ② 在静态代码块 不能在构造器中赋值。
        4)final类不能继承,但是可以实例化对象。
        5)如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
        6)一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
        7)final不能修饰构造方法(即构造器)。
        8)final 和 static 往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理。
        9)包装类(Integer,Double,Float,Boolean等都是final),String也是final类。

        public int addOne(final int x) { //下面的代码是否有误,为什么 ? //这里也可以
                ++x; //错误, 原因是不能修改 final x 的值 
                return x + 1; //这里是可以. 
        }


六、抽象类

1、 当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract 来修饰该类就是抽象类。
        

2、 抽象类的介绍
        1)用abstract 关键字来修饰一个类时,这个类就叫抽象类
                访问修饰符 abstract 类名{
                }
        2)用abstract 关键字来修饰一个方法时,这个方法就是抽象方法
                访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
        3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
        4)抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多 

3、抽象类使用的注意事项和细节讨论
        1)抽象类不能被实例化
        2)抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
        3)一旦类包含了abstract方法,则这个类必须声明为abstract
        4)abstract 只能修饰类和方法,不能修饰属性和其它的
        5)抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法,构造器、静态属性等等
        6)抽象方法不能有主体,即不能实现
                abstract void aaa()
        7)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法。除非它自己也声明为abstract类。
        8)抽象方法不能使用private、final 和 static来修饰,因为这些关键字都是和重写相违背的。


七、抽象类最佳实践-模板设计模式

1、基本介绍
        抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

2、模板设计模式能解决的问题
        1)当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
        2)编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。

3、最佳实践
        
1)有多个类,完成不同的任务job
        2)要求统计得到各自完成任务的时间
        
        0401_韩顺平Java_抽象模板模式_哔哩哔哩_bilibili


 八、接口

         

1、基本介绍
        接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
        语法:
        interface 接口名{
                /属性
                //抽象方法
        }
        class 类名 implements 接口{
                自己属性;
                自己方法;
                必须实现的接口的抽象方法
        }
        小结:接口是更加抽象的抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体【jdk7.0】。接口体现了程序设计的多态和高内聚低偶合的设计思想。
        特别说明:Jdk8.0后接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。
        

2、注意事项和细节
        1)接口不能被实例化
        2)接口中所有的方法是 public方法,接口中抽象方法,可以不用abstract 修饰 图示:
        void aaa();实际上是 abstract void aa();
        
        3)一个普通类实现接口,就必须将该接口的所有方法都实现。可以使用 alt+enter 来解决。
        4)抽象类实现接口,可以不用实现接口的方法。 
        5)一个类同时可以实现多个接口
        6)接口中的属性,只能是final的,而且是 public static final 修饰符。
        比如:int a=1;实际上是 public static final int a=1;(必须初始化)
        7)接口中属性的访问形式: 接口名.属性名
        8)接口不能继承其它的类,但是可以继承多个别的接口
        interface A extends B,C{}
        9)接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的。
        

3、实现接口 & 继承类
        

        接口和继承解决的问题不同:
        继承的价值主要在于:解决代码的复用性和可维护性。
        接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。即更加的灵活。
        接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足 like-a的关系。
        接口在一定程度上实现代码解耦 [即:接口规范性+动态绑定机制]

        当子类继承了父类,就自动的拥有父类的功能, 如果子类需要扩展功能,可以通过实现接口的方式扩展可以理解 实现接口 是 对 java 单继承机制的一种补充

4、接口的多态特性
        1)多态参数
        UsbInterface usb,既可以接收手机对象,又可以接收相机对象,就体现了 接口 多态(接口引用可以指向实现了接口的类的对象)
        2)多态数组
        :给Usb数组中,存放 Phone 和 相机对象,Phone类还有一个特有的方法cal(),请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,还需要调用Phone 特有方法 call。
        
        3)接口存在多态传递现象
        


 九、内部类(四种)

        如果定义类在局部位置( 方法中 / 代码块)
        (1) 局部内部类
(2) 匿名内部类 
        定义在成员位置,本质就是一个成员
        (1) 成员内部类
(2) 静态内部类
 

1、基本介绍
        一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员。
        【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】
        内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
        注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。

2、基本语法 
        class Outer{ //外部类
                class lnner{//内部类
                }
        }
        class Other{//外部其他类
        }

3、内部类的分类
        定义在外部类局部位置上(比如方法内):
        1)局部内部类(有类名)
        2)匿名内部类(没有类名,重点!!!!!!!!)
        定义在外部类的成员位置上:
        1)成员内部类(没用static修饰)
        2)静态内部类(使用static修饰)

4、局部内部类的使用

局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
        1)可以直接访问外部类的所有成员,包含私有的
        2)不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final 修饰,因为局部变量也可以使用final
        3)作用域:仅仅在定义它的方法或代码块中
        4)局部内部类---访问---->外部类的成员【访问方式:直接访问】
        5)外部类---访问---->局部内部类的成员
                访问方式:创建对象,再访问(注意:必须在作用域内)
        记住:
        (1)局部内部类定义在方法中 / 代码块
        (2)作用域在方法体或者代码块中
        (3)本质仍然是一个类 

        6)外部其他类---不能访问----->局部内部类(因为 局部内部类地位是一个局部变量)
        7)如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)
        外部类名.this 本质就是外部类的对象, 即哪个对象调用了 外部类方法,外部类.this 就是哪个对象

package com.hspedu.innerclass;
/*** 演示局部内部类的使用*/
public class LocalInnerClass {//public static void main(String[] args) {Outer02 outer02 = new Outer02();outer02.m1();System.out.println("outer02 的 hashcode=" + outer02);}
}
class Outer02 {//外部类private int n1 = 100;private void m2() {System.out.println("Outer02 m2()");}//私有方法public void m1() {//方法//1.局部内部类是定义在外部类的局部位置,通常在方法//3.不能添加访问修饰符,但是可以使用 final 修饰//4.作用域 : 仅仅在定义它的方法或代码块中final class Inner02 {//局部内部类(本质仍然是一个类)//2.可以直接访问外部类的所有成员,包含私有的private int n1 = 800;public void f1() {//5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1 和 m2()//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,// 使用 外部类名.this.成员)去访问// 老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1);System.out.println("Outer02.this hashcode=" + Outer02.this);m2();}}//6. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可Inner02 inner02 = new Inner02();inner02.f1();}
}

 5、匿名内部类的使用 ※※※

        1)本质是类
        2)内部类
        3)该类没有名字
        4)同时还是一个对象
        说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

        匿名内部类的基本语法:
        new 类或接口(参数列表){
                类体
        };

        ① 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对代码分析可以看出这个特点,因此可以调用匿名内部类方法。
        ② 可以直接访问外部类的所有成员,包含私有的。
        ③ 只不能添加访问修饰符,因为它的地位就是一个局部变量。
        ④ 作用域:仅仅在定义它的方法或代码块中。
        ⑤ 匿名内部类---访问---->外部类成员[访问方式:直接访问]。
        ⑥ 外部其他类---不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)。
        ⑦ 如果外部类和匿名内部类的成员重名时,医名内部类访问的话,默认遵循就近原则如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

package com.hspedu.innerclass;
/*** 演示匿名内部类的使用*/
public class AnonymousInnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}
class Outer04 { //外部类private int n1 = 10;//属性public void method() {//方法
//基于接口的匿名内部类
//老韩解读
//1.需求: 想使用 IA 接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger 的编译类型 ? IA
//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用IA tiger = new IA() {@Overridepublic void cry() {System.out.println("老虎叫唤...");}};System.out.println("tiger 的运行类型=" + tiger.getClass());tiger.cry();tiger.cry();tiger.cry();
// IA tiger = new Tiger();
// tiger.cry();
//演示基于类的匿名内部类
//分析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
//5. 注意("jack") 参数列表会传递给 构造器Father father = new Father("jack"){@Overridepublic void test() {System.out.println("匿名内部类重写了 test 方法");}};System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2father.test();
//基于抽象类的匿名内部类Animal animal = new Animal(){@Overridevoid eat() {System.out.println("小狗吃骨头...");}};animal.eat();}
}
interface IA {//接口public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类public Father(String name) {//构造器System.out.println("接收到 name=" + name);}public void test() {//方法}
}
abstract class Animal { //抽象类abstract void eat();
}
package com.hspedu.innerclass;
public class AnonymousInnerClassDetail {public static void main(String[] args) {Outer05 outer05 = new Outer05();outer05.f1();
//外部其他类---不能访问----->匿名内部类System.out.println("main outer05 hashcode=" + outer05);}
}
class Outer05 {private int n1 = 99;public void f1() {
//创建一个基于类的匿名内部类
//不能添加访问修饰符,因为它的地位就是一个局部变量
//作用域 : 仅仅在定义它的方法或代码块中Person p = new Person(){private int n1 = 88;@Overridepublic void hi() {
//可以直接访问外部类的所有成员,包含私有的
//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问System.out.println("匿名内部类重写了 hi 方法 n1=" + n1 +" 外部内的 n1=" + Outer05.this.n1 );
//Outer05.this 就是调用 f1 的 对象System.out.println("Outer05.this hashcode=" + Outer05.this);}};p.hi();//动态绑定, 运行类型是 Outer05$1
//也可以直接调用, 匿名内部类本身也是返回对象
// class 匿名内部类 extends Person {}
// new Person(){
// @Override
// public void hi() {
// System.out.println("匿名内部类重写了 hi 方法,哈哈...");
// }
// @Override
// public void ok(String str) {
// super.ok(str);
// }
// }.ok("jack");}
}
class Person {//类public void hi() {System.out.println("Person hi()");}public void ok(String str) {System.out.println("Person ok() " + str);}
}
//抽象类/接口...

匿名内部类实践

 当做实参传递,简洁有效。

public class InnerClassExercise01 {public static void main(String[] args) {
//当做实参直接传递,简洁高效f1(new IL() {@Overridepublic void show() {System.out.println("这是一副名画~~...");}});
//传统方法f1(new Picture());}//静态方法,形参是接口类型public static void f1(IL il) {il.show();}
}
//接口
interface IL {void show();
}
//类->实现 IL => 编程领域 (硬编码)
class Picture implements IL {@Overridepublic void show() {System.out.println("这是一副名画 XX...");}
}

 6、成员内部类的使用

        说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
        1)可以直接访问外部类的所有成员,包含私有的。
        
        2)可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员。
        3)作用域和外部类的其他成员一样,为整个类体,如 在外部类的成员方法中创建成员内部类对象,再调用方法。
        4)成员内部类---访问---->外部类成员(比如:属性)【访问方式:直接访问】
        5)外部类---访问------>成员内部类(说明)【访问方式:创建对象,再访问】
        6)外部其他类---访问---->成员内部类【两种方式】
        7)如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

package com.lty;public class MemberInnerClass01 {public static void main(String[] args) {Outer08 outer08 = new Outer08();outer08.t1();//外部其他类,使用成员内部类的三种方式//老韩解读// 第一种方式// outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员// 这就是一个语法,不要特别的纠结. Outer08.Inner08 inner08 = outer08.new Inner08();inner08.say();// 第二方式 在外部类中,编写一个方法,可以返回 Inner08 对象Outer08.Inner08 inner08Instance = outer08.getInner08Instance();inner08Instance.say();}
}
class Outer08 { //外部类private int n1 = 10;public String name = "张三";private void hi() {System.out.println("hi()方法...");}//1.注意: 成员内部类,是定义在外部内的成员位置上//2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员public class Inner08 {//成员内部类private double sal = 99.8;private int n1 = 66;public void say() {//可以直接访问外部类的所有成员,包含私有的//如果成员内部类的成员和外部类的成员重名,会遵守就近原则. //,可以通过 外部类名.this.属性 来访问外部类的成员System.out.println("n1 = " + n1 + " name = " + name + " 外部类的 n1=" + Outer08.this.n1);hi();}}//方法,返回一个 Inner08 实例public Inner08 getInner08Instance(){return new Inner08();}//写方法public void t1() {//使用成员内部类//创建成员内部类的对象,然后使用相关的方法Inner08 inner08 = new Inner08();inner08.say();System.out.println(inner08.sal);}
}

 

7、静态内部类

        说明:静态内部类是定义在外部类的成员位置,并且有static修饰
        1)可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
        2)可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
        3)作用域:同其他的成员,为整个类体
        4)静态内部类---访问---->外部类(比如:静态属性)【访问方式:直接访问所有静态成员】
        5)外部类---访问------>静态内部类 访问方式:创建对象,再访问
        6)外部其他类---访问----->静态内部类
                ① new外部类名.静态内部类
                ② 编写非静态/静态方法返回对象实例
        7)如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问

package com.lty;
public class StaticInnerClass01 {public static void main(String[] args) {Outer10 outer10 = new Outer10();outer10.m1();//外部其他类 使用静态内部类//方式 1//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)Outer10.Inner10 inner10 = new Outer10.Inner10();inner10.say();//方式 2//编写一个方法,可以返回静态内部类的对象实例. Outer10.Inner10 inner101 = outer10.getInner10();System.out.println("============");inner101.say();Outer10.Inner10 inner10_ = Outer10.getInner10_();System.out.println("************");inner10_.say();}
}
class Outer10 { //外部类private int n1 = 10;private static String name = "张三";private static void cry() {}static class Inner10 {private static String name = "韩顺平教育";public void say() {//如果外部类和静态内部类的成员重名时,静态内部类访问的时,//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)System.out.println(name + " 外部类 name= " + Outer10.name);cry();}}public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问Inner10 inner10 = new Inner10();inner10.say();}public Inner10 getInner10() {return new Inner10();}public static Inner10 getInner10_() {return new Inner10();}
}

 


http://www.xdnf.cn/news/2894.html

相关文章:

  • EPSG的作用
  • C++23中的std::forward_like:完美转发的增强
  • 第十六届蓝桥杯 2025 C/C++B组第一轮省赛 全部题解(未完结)
  • 探索目标检测:边界框与锚框的奥秘
  • leetcode 21. 合并两个有序链表(c++解法+相关知识点复习)
  • 目标检测和目标跟踪的区别与联系
  • 大前端开发——前端知识渐变分层讲解 利用金字塔原理简化前端知识体系
  • 长短期记忆网络(LSTM)
  • MySQL多表操作
  • Ansible 铸就 Linux 安全之盾(Ansible Builds Linux Security Shield)
  • 《软件测试52讲》学习笔记:如何设计一个“好的“测试用例?
  • 【学习资源】知识图谱与大语言模型融合
  • 在Mybatis中写sql的常量应用
  • 万物皆可执行:多功能机器人正在定义新生产力法则
  • Ceph IO读写流程详解(二)——RADOSGW请求处理
  • Lightroom 2025手机版:专业编辑,轻松上手
  • 基于 STM32 的智慧图书馆智能控制系统设计与实现
  • DeepSeek破界而来:重构大规模深度检索的算力与边界
  • Java云原生+quarkus
  • 1.1探索 LLaMA-Factory:大模型微调的一站式解决方案
  • Consul安装部署(Windows环境)
  • 链表反转_leedcodeP206
  • 判断图片url损坏无法展示工具类
  • UE5 Set actor Location和 Set World Location 和 Set Relative Location 的区别
  • 关于本地端口启动问题
  • JAVA--- 关键字static
  • 长效住宅IP是什么?如何获取长效住宅IP?
  • 工程管理部绩效考核关键指标与项目评估
  • 选择排序快速排序
  • 国标GB28181视频平台EasyCVR实用方案:如何实现画面拉伸