今日语录:佛说:生死疲劳,从贪欲起;少欲无为,身心自在。
一、类变量和类方法
1、类变量(静态变量)
-
类变量的内存布局
1、static变量是对象共享不管static变量在哪里
2、static变量是同一个类所有对象共享
3、static类变量,在类加载的时候就生成了
4、类变量是随着类的加载而创建,所以即使没有创建对象实例也是可以访问的
-
什么是类变量
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
-
如何定义类变量
访问修饰符 static 数据类型 变量名;(推荐)
static 访问修饰符 数据类型 变量名; -
如何访问类变量
类名.类变量名
or
对象名.类变量名【静态变量的访问修饰符的访问权限和范围 和 普通属性是一样的】
推荐使用:类名.类变量名 -
类变量的使用注意事项和细节
1、什么时候需要类变量
当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量);
2、类变量与示例变量(普通属性)的区别
类变量是该类的所有对象共享的,而实例变量是每个对象独享的
3、加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
4、类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,但java设计者推荐我们使用:类名.类变量名 方式访问【前提是:满足访问修饰符的访问权限和范围】
5、实例变量不能通过 类名.类变量名 方式访问
6、类变量是在类加载的时候就初始化了,也就是说,即使你没创建对象,只要类加载了,就可以使用类变量
7、类变量的生命周期是随着类的加载开始,随着类的消亡而销毁
2、类方法(静态方法)
-
简介
类方法也叫静态方法
形式如下:
访问修饰符 static 数据返回类型 方法名(){ } 【推荐写法】
static 访问修饰符 s数据返回类型 方法名(){ } -
类方法的调用:
使用方式:类名.类方法名 或者 对象名.类方法名【前提是 满足访问修饰符的访问权限和范围】
-
类方法经典的使用场景
1、当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率
比如:工具类中的方法 utils
Math类,Arrays类,Collections类
2、小结
在程序员实际开发中,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象时就可以调用,比如打印一维数组,冒泡排序,完成某个计算任务
-
类方法使用注意事项和细节
1、类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:
类方法中无this的参数
普通方法中隐含无this的参数
2、类方法可以通过类名调用,也可以通过对象名调用
3、普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用
4、类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以
5、类方法(静态方法)中,只能访问静态变量 或 静态方法
6、普通成员方法,既可以访问 普通变量(方法),也可以访问静态变量(方法)
小结
静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员(必须遵守访问权限)
二、理解main方法语法
-
深入理解main方法
解释main方法的形式:public static void main(String[] args){}
1、java虚拟机需要调用类的main(),所以该方法的访问权限必须是public
2、java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static
3、该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
4、java执行的程序
-
特别提示
1、在main()方法中,我们可以直接调用main方法所在类的静态方法访问静态属性
2、不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
三、代码块
-
简介
代码块又称为初始化块,属于类中的成员【即 是类的一部分】,类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用
-
基本语法
[修饰符]{
代码
};
-
注意
1、修饰符可选,要写的话,也只能写static
2、代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块
3、逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
4、;号可以协商,也可省略
-
代码块使用注意事项和细节
1、static代码块也叫进芒果台代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行
2、类什么时候加载
1、创建对象实例时(new)
2、创建子类对象实例,父类也会被加载
3、实用类的静态成员时(静态属性,静态方法)
3、普通的代码块,在创建对象实例时,会被隐式的调用
被创建一次,就会调用一次
如果只会使用类的静态成员时,普通代码块并不会执行
小结:
1、static代码块是类加载时,执行,只会执行一次
2、普通代码块是在创建对象时调用
4、创建一个对象时,在一个类调用顺序是:
1、调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
2、调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通态代码块和多个普通属性初始化,则按他们定义的顺序调用)
5、构造方法(构造器)的最前面其实隐含了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此优先于构造器和普通代码块执行的
6、创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
1、父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
2、子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
3、父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
4、父类的构造方法
5、子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
6、子类的构造方法
7、静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
四、单例设计模式
-
什么是设计模式
1、静态方法和属性的经典使用
2、设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索
-
什么是单例模式
单例(单个实例)
1、所谓类的单例设计模式,就是采取一个固定的方法保证整个的软件系统中,对某个类只能创建一个对象实例,并且该类只提供一个取得其对象实例的方法
2、单例模式有两种方法:
【饿汉式】
1 将构造器私有化=>防止在类的外面直接创建
2 在类的内部直接创建对象(该对象是static)
3 提供一个公共的static方法,返回该对象
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;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + ''' +
'}';
}
}【懒汉式】
1 构造器私有化
2 定义一个static静态属性对象
3 提供一个Public的static方法,可以返回一个对象
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);
//再次調用getInstance
Cat 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;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + ''' +
'}';
}
} -
饿汉式和懒汉式区别
1、二者最主要的区别在于创建对象的时机不同,饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建
2、饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
3、饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
4、在我们java SE标准类中,java.lang.Runtime就是经典的单例模式
五、final关键字
-
基本介绍
final可以修饰类、属性、方法和局部变量
在以下情况,,需要用到final
1、当不希望类被继承时
2、当不希望父类的某个方法被子类覆盖或重写时
3、当不希望类的某个属性的值被修改
4、当不希望某个局部变量被修改
-
使用注意事项和细节
1、final修饰的属性又叫常量,一般用xx_xx_xx命名
2、final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一
1、定义时:如public final double TAX_TATE = 0.08;
2、在构造器中
3、在代码块中
3、如果final修饰的属性是静态的,则初始化的位置只能是
1、定义时
2、在静态代码块 不能再构造器中赋值
4、final类不能继承,但是可以实例化对象
5、如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
6、一般来说,如果一个类已经是final类了,就没必要再将方法修饰成final方法
7、final不能修饰构造方法(构造器)
8、final和static往往搭配使用,效果更高,底层编译器做了优化处理
class Demo{
public static final int i = 16;
static{
System.out.println("韩顺平教育~");
}
}9、包装类(Integer,Double,Float,Boolean等都是final),String也是final类
六、抽象类
-
小结
当父类的某些方法,需要声明,但是又不能确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类,用abstract来修饰该类就是抽象类。
-
抽象类的介绍
1、用abstract关键字来修饰一个类时,这个类就是抽象类
2、用abstract关键字来修饰一个方法,这个方法就是抽象方法
访问修饰符 abstract 返回类型 方法名(参数列表)
3、抽象类的价值更多作用是在于设计,是设计者设计好之后,让子类继承并实现抽象类
4、抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多
-
抽象类使用的注意事项和使用细节
1、抽象类不能被实例化
2、抽象类不一定要包含abstract方法,也就是说,抽象类可以没有abstract
方法
3、一旦类包含了abstract方法,则这个类必须声明为abstract
4、abstract只能修饰类和方法,不能修饰属性和其他的
5、抽象类可以有任意成员【因为抽象类还是类】,比如:非抽象方法、构造器、静态属性等等
6、抽象方法不能有主体,即不能实现
7、如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstarct类

七、抽象类最佳实践-模板设计模式
-
最佳实践
设计一个抽象类(Template)能完成以下功能:
1、编写方法calculateTime(),可以计算某段代码的耗用时间
2、编写抽象方法code();
3、编写一个子类Sub,继承抽象类Template,并实现code方法
4、编写一个测试类TestTemplate,看看是否好用
package com.hspedu.abstract_;
abstract public class Template { //抽象类-模板设计模式
public abstract void job();//抽象方法
public void calculateTime() {//实现方法,调用job方法
//得到开始的时间
long start = System.currentTimeMillis();
job(); //动态绑定机制
//得的结束的时间
long end = System.currentTimeMillis();
System.out.println("任务执行时间 " + (end - start));
}
}package com.hspedu.abstract_;
public class AA extends Template {
//计算任务
//1+....+ 800000
@Override
public void job() { //实现Template的抽象方法job
long num = 0;
for (long i = 1; i <= 800000; i++) {
num += i;
}
}
// public void job2() {
// //得到开始的时间
// long start = System.currentTimeMillis();
// long num = 0;
// for (long i = 1; i <= 200000; i++) {
// num += i;
// }
// //得的结束的时间
// long end = System.currentTimeMillis();
// System.out.println("AA 执行时间 " + (end - start));
// }
}package com.hspedu.abstract_;
public class BB extends Template{
public void job() {//这里也去,重写了Template的job方法
long num = 0;
for (long i = 1; i <= 80000; i++) {
num *= i;
}
}
}package com.hspedu.abstract_;
public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime(); //这里还是需要有良好的OOP基础,对多态
BB bb = new BB();
bb.calculateTime();
}
}
八、接口
-
基本介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法实现出来。
语法:
interface 接口名{
// 属性
// 方法(1、抽象方法 2、默认实现方法3、静态方法)
}
class 类名 implements 接口{
自己属性;
自己方法;
必须实现的接口的抽象方法
}
小结:
1、在jdk7.0以前,接口里的所有方法都没有方法体,即都是抽象方法
2、jdk8.0后接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现 -
注意事项和使用细节
1、接口不能被实例化
2、接口中所有方法是public方法,接口中抽象方法,可以不用abstract关键字修饰
void aaa();
==> 实际上是:abstract void aaa();3、一个普通类实现接口,就必须将该接口的所有方法都实现(IDEA可以使用快捷键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和默认,这点和类的修饰符是一样的

1、接口 VS继承
package com.hspedu.interface_;
public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey wuKong = new LittleMonkey("悟空");
wuKong.climbing();
wuKong.swimming();
wuKong.flying();
}
}
//猴子
class Monkey {
private String name;
public Monkey(String name) {
this.name = name;
}
public void climbing() {
System.out.println(name + " 会爬树...");
}
public String getName() {
return name;
}
}
//接口
interface Fishable {
void swimming();
}
interface Birdable {
void flying();
}
//继承
//小结: 当子类继承了父类,就自动的拥有父类的功能
// 如果子类需要扩展功能,可以通过实现接口的方式扩展.
// 可以理解 实现接口 是 对java 单继承机制的一种补充.
class LittleMonkey extends Monkey implements Fishable,Birdable {
public LittleMonkey(String name) {
super(name);
}
@Override
public void swimming() {
System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳...");
}
@Override
public void flying() {
System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔...");
}
}
-
实现接口vs继承类
1、接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计,设计好各种规范(方法),让其他类去实现这些方法
2、接口比继承更加灵活
接口比继承更加灵活,继承是满足is – a 的关系,而接口只需要满足like – a的关系
3、接口在一定程度上实现代码的解耦[即:接口规范性 + 动态绑定机制]
2、接口多态特性
1、多态参数
2、多态数组
3、接口存在多态传递现象
九、内部类
-
基本介绍
一个类的内部又完整嵌套了另一个类。被嵌套的类称为内部类(inner class),嵌套其它类的类称为外部类(outer class)。是我们类的第五大成员,内部类最大的特点是可以直接访问私有属性,并且可以体现类与类之间的包含关系。注意:内部类是学习的难点。同时也是重点,后面看底层源码时,也有大量的内部类。
PS:类的五大成员
1、属性
2、方法
3、构造器/构造方法
4、代码块
5、内部类
-
基本语法
class Outer{ //外部类
class Inner{ // 内部类
}
}
class other{ // 外部其他类
} -
内部类的分类
1、定义在外部类局部位置上(比如方法内):
A、局部内部类(有类名)
B、匿名内部类(没有类名,重点)
2、定义在外部类的成员位置上:A、成员内部类(没有static修饰)
B、静态内部类(有static修饰)
1、局部内部类
-
说明
-
局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
1、可以直接访问外部类的所有成员,包括私有的
2、不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
3、作用域:仅仅在定义它的方法或代码块中
4、局部内部类—访问—>外部类的成员【访问方式:直接访问】
5、外部类—访问—->局部类变量【访问方式:创建对象,再访问(注意:必须在作用域内)】
6、外部其它类—不能访问—->局部内部类(因为 局部内部类 地位就是一个局部变量)
7、如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.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();
}
}
2、匿名内部类
-
说明
匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
-
基本语法
new 类或接口(参数列表){
类体
};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() {
@Override
public 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"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void 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();
} -
匿名内部类的使用和注意事项
1、匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时本身也是一个对象,因此从语法上看,它既有类的特征,也有创建对象的特征,因此可以调用匿名内部类方法。
代码片段示例一:
new A(){
@Override
public void cry(){
System.out.println("Hi");
}
}.cry();
代码片段示例二:
A a = new A(){
@Override
public void cry(){
System.out.println("Hi");
}
};
a.cry();2、可以直接访问外部类的所有成员,包含私有的
3、不能添加访问修饰符,因为它的地位就是一个局部变量
4、作用域:仅仅在定义他的方法或代码块中
5、匿名内部类—-访问—–>外部类成员【访问方式:直接访问】
6、外部其他类—-不能访问——>匿名内部类(因为匿名内部类地位就是一个局部变量)
7、如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
-
匿名内部类最佳实践
1、当作实参直接传递,简洁高效
/**
* @author chenx
* @date 2021年11月27日
*/
public class Inner {
public static void main(String[] args) {
fun(new IE(){
@Override
public void show(){
System.out.println("匿名内部类");
}
});
}
public static void fun(IE ie){
ie.show();
}
}
interface IE{
void show();
}package com.hspedu.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
/*
1.有一个铃声接口Bell,里面有个ring方法。(右图)
2.有一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型(右图)
3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
*/
CellPhone cellPhone = new CellPhone();
//老韩解读
//1. 传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
//2. 重写了 ring
//3. Bell bell = new Bell() {
// @Override
// public void ring() {
// System.out.println("懒猪起床了");
// }
// }
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{ //接口
void ring();//方法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是Bell接口类型
System.out.println(bell.getClass());
bell.ring();//动态绑定
}
}
3、成员内部类
1、成员内部类是定义在外部类的成员位置,并且没有static修饰
2、可以直接访问外部类的所有成员,包括私有的
3、可以添加任意访问修饰符(public protected 默认 private),因为它的地位就是一个成员
4、作用域和外部类的其他成员一样,为整个类体。在外部类的成员方法中创建成员内部类对象,再调用方法
5、成员内部类—-访问—->外部类(比如:属性)【访问方式:直接访问】
6、外部类—-访问—–内部类【访问方式:创建对象,再访问】
7、外部其他类—访问—>成员内部类
8、如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,可以通过:外部类名.this.成员,去访问
package com.hspedu.innerclass;
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);
}
}
4、静态内部类
1、说明:静态内部类时定义在外部类的成员位置,并且有static修饰
2、可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员
3、可以添加任意访问修饰符(public protected 默认 private),因为它的地位就是一个成员
4、作用域:同其他的成员,为整个类体
5、静态内部类—访问—->外部类成员【访问方式:直接访问外部类成员】
6、外部类—–访问—->静态内部类【访问方式:创建对象,再访问】
7、外部其他类—–访问—–>静态内部类【有两种方式】
方式一:Outer10.Inner10 inner10 = new Outer10.Inner10();
方式二:编写一个方法,可以返回静态内部类的对象实例.
8、如果外部类和静态内部类的成员重名时,静态内部类访问的时候,默认遵循就近原则,如果想访问外部类的成员,则可以用(外部类名.成员)去访问
public Inner10 getInner10() {
return new Inner10();
}
Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("============");
inner101.say();package com.hspedu.innerclass;
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() {}
//Inner10就是静态内部类
//1. 放在外部类的成员位置
//2. 使用static 修饰
//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
//4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
//5. 作用域 :同其他的成员,为整个类体
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();
}
}
5、小结
1、内部类有四种:局部内部类,匿名内部类、成员内部类、静态内部类
2、匿名内部类是重点
new 类/接口(参数列表){
//…..
};
3、成员内部类,静态内部类是放在外部类的成员位置,本质就是一个成员,可以添加任意修饰符
原文始发于微信公众号(Whisper Coding):Java入门-面向对象(进阶)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/255455.html