韩顺平老师的零基础30天学会Java,(小白自学)自己看的写的当记忆,如有不对地方感谢指教
内部类介绍
- 内部类:在一个类的内部定义的类。
- 成员内部类格式如:
class Outer{//外部类 class Inner{}//内部类 }
public class l6 {// 外部其他类
public static void main(String[] args) {
}
}
class Outer {// 外部类
private int n1 = 100;// 属性
public Outer(int n1) {// 构造器
this.n1 = n1;
}
public void m1() {// 方法
System.out.println("m1()");
}
{// 代码块
System.out.println("代码块la");
}
class Innter {// 内部类,在Outer类的内部
}
}
- 类的五大成员:属性,方法,构造器,代码块,内部类
- 内部类分类:局部内部类,匿名内部类,成员内部类,静态内部类
局部内部类
- 局部内部类:定义在外部类的局部位置,比如方法中+有类名(LocalInnterClass)
- 可以直接访问外部类的所有成员,包含私有的
class Outer {// 外部类
private int n1 = 100;// 属性
public void m1() {// 方法
// 1.局部内部类是定义在外部类的局部位置,通常是在方法里
System.out.println("m1()");
class Innter {// 本质还是一个类:内部类
// 2.可以直接访问外部类的所有成员,包含私有
public void f1() {
System.out.println("n1" + n1);
m1();
}
}
}
}
- 不能添加访问修饰符,因为他的地位就是一个局部变量,局部变量不能使用。但是可以用final修饰
class Innter {// 本质还是一个类:内部类
// 2.可以直接访问外部类的所有成员,包含私有
public void f1() {
System.out.println("n1" + n1);
m1();
}
}
class Innter1 extends Innter {
}
}
- 作用域:仅在定义它的方法中或代码块中
- 外部类如何使用Innter呢?——外部类在方法中,可以创建Innter对象,然后调用方法即可
// 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
Innter innter = new Innter();
innter.f1();
- 局部内部类定义在方法中/代码块中
- 作用域在方法体或代码块中
- 本质仍是个类
public class l6 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m1();
}
}
class Outer {// 外部类
private int n1 = 100;// 属性
public void m2() {
System.out.println("m2");
}
public void m1() {// 方法
// 1.局部内部类是定义在外部类的局部位置,通常是在方法里
// 4.作用域:仅在此方法中或代码块
System.out.println("m1()");
final class Innter {// 本质还是一个类:内部类
// 2.可以直接访问外部类的所有成员,包含私有
public void f1() {
System.out.println("n1" + n1);
m2();
}
}
// 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
Innter innter = new Innter();
innter.f1();
}
}
- 外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
Outer.this本质上就是外部类的对象,哪个对象调用了m1,Outer.this就是哪个对象,这里就是outer对象
public class l6 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m1();
}
}
class Outer {// 外部类
private int n1 = 100;// 属性
public void m2() {
System.out.println("m2");
}
public void m1() {// 方法
// 1.局部内部类是定义在外部类的局部位置,通常是在方法里
// 4.作用域:仅在此方法中或代码块
System.out.println("m1()");
final class Innter {// 本质还是一个类:内部类
// 2.可以直接访问外部类的所有成员,包含私有
private int n1 = 10;
public void f1() {
// 7.如果外部类和内部类的成员重名时,就近原则。如果要使用外部类的成员(外部类名.this.成员)
System.out.println("n1=" + n1 + "外部类的n1" + Outer.this.n1);
m2();
}
}
// 6.外部类调用内部类可在方法中,创建Innter对象,再调用方法即可
Innter innter = new Innter();
innter.f1();
}
}
- 这里用hashcode显示地址来证明到底对应是不是outer地址一致,对滴
匿名内部类!!!
- 匿名内部类:1)本质是类2)内部类3)该类没有名字【其实系统底层是给分配的名字,隐藏起来的】4)同时还是个对象Anonymous
- 匿名内部类基本语法:
new 类或接口(参数列表){类体};
- 基于接口的匿名内部类
(1)需求:想使用接口,并创建对象
(2)传统方法,写一个类实现该接口,并创建对象
public class l6 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
class Outer {
private int n1 = 10;// 属性
public void method() {// 方法
// 基于接口的匿名内部类
IA tiger = new Triger();
tiger.cry();
}
}
interface IA {// 接口
public void cry();
}
class Triger implements IA {
@Override
public void cry() {
System.out.println("老虎咆哮");
}
}
class Father {
public Father() {// 构造器
}
public void test() {// 方法
}
}
(3)如果需求是Tiger类只使用一次以后再不使用,这样话每次。。。繁琐
(4)使用匿名类来简化
public class l6 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
class Outer {
private int n1 = 10;// 属性
public void method() {// 方法
// 基于接口的匿名内部类
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎咆哮");
}
};
tiger.cry();
// IA tiger = new Triger();
// tiger.cry();
}
}
interface IA {// 接口
public void cry();
}
// class Triger implements IA {
// @Override
// public void cry() {
// System.out.println("老虎咆哮");
// }
// }
class Father {
public Father() {// 构造器
}
public void test() {// 方法
}
}
(5)tiger的编译类型:IA
(6)tiger的运行类型:匿名内部类
class Outer$1。以后看到XXX$1就是匿名内部类,getClass就是获取到该对象的运行类型
- 编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
(7)jdk底层在创建匿名内部类 Outer$1,立刻马上就创建了 Outer$1实例,并且把地址返回给tiger
(8)匿名内部类使用一次,就不能载使用的
- 演示基于类的匿名内部类
father编译类型 Father
father运行类型 Outer$2
Father father = new Father(){};
father编译类型 Father
father运行类型 Father
Father father = new Father() ;
- 基于抽象类的匿名内部类
abstract class Animal {// 抽象类
abstract void eat();
}
这里就不能省省略不写方法。。。抽象。。。有点像父类和子类
Father father = new Father("jack") {
@Override
public void test() {
System.out.println("iuyinm");
}
};
class Father {
public Father(String name) {// 构造器
System.out.println("name=" + name);
}
public void test() {// 方法
}
}
编译结果:name=jack
- 两种调用方法
(1)通过对象调用
public class l6 {
public static void main(String[] args) {
Outer05 outer = new Outer05();
outer.f1();
}
}
class Outer05 {
private int n1 = 90;
public void f1() {
// 创建一个基于类的匿名内部类
Person person = new Person() {
@Override
public void hi() {
System.out.println("匿名内部类重写了hi方法");
}
};
person.hi();// 动态绑定,真实运行类型是Outer05$1
}
}
class Person {
public void hi() {
System.out.println("Person hi");
}
}
(2)直接调用其本身也是返回对象
public class l6 {
public static void main(String[] args) {
Outer05 outer = new Outer05();
outer.f1();
}
}
class Outer05 {
private int n1 = 90;
public void f1() {
// 创建一个基于类的匿名内部类
// Person person = new Person() {
// @Override
// public void hi() {
// System.out.println("匿名内部类重写了hi方法");
// }
// };
// person.hi();// 动态绑定,真实运行类型是Outer05$1
// 也可以直接调用,匿名内部类本身也是返回对象
new Person() {
@Override
public void ok(String str) {
super.ok(str);
}
@Override
public void hi() {
System.out.println("匿名内部类重写了hi方法。。。");
}
}.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 l6 {
public static void main(String[] args) {
// 当作实参直接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println("这是一幅名画");
}
});
}
// 静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
// 接口
interface IL {
void show();
}
再看看传统写法
public static void main(String[] args) {
// 当作实参直接传递,简洁高效
// f1(new IL() {
// @Override
// public void show() {
// System.out.println("这是一幅名画");
// }
// });
// 传统方法
f1(new Car());
}
// 静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
// 接口
interface IL {
void show();
}
// 类实现IL 编程领域中被称为硬编码
class Car implements IL {
@Override
public void show() {
System.out.println("这也是一副名画");
}
}
比如说。要是改了Car里面的”这也是一副名画“,那上面调用静态方法那调用都影响
// 1.传递的是实现了Bell接口的匿名内部类 l6$1 l6$2
// 2.重写了ring方法
// 3.Bell bell=new Bell() {
// @Override
// public void ring() {
// System.out.println("懒猪起床了");
// }
// }
bell.ring();// 动态绑定
public class l6 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴们上课了");
}
});
}
}
interface Bell {// 接口
public void ring();// 方法
}
class Cellphone {// 类
public void alarmclock(Bell bell) {// 形参是Bell接口类型
bell.ring();
}
}
成员内部类
- 成员内部类定义:定义在外部类的成员位置,且没有static修饰(MemberInnerClass)
- 可直接访问外部类的所有成员,包含私有
- 可以添加任意修饰符(public,protected,默认,private),因为其就是一个成员
public class l6 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.ti();
}
}
class Outer08 {// 外部类
private int n1 = 10;
public String name = "凌不疑";
protected class Innter08 {// 1.成员内部类(即不再方法中也不在代码块中,在成员的位置上写)
// 2.可以添加任意修饰符(public,protected,默认,private),因为他本身地位就是成员
public void say() {
System.out.println("Outer的n1=" + n1 + "Outer的name=" + name);
}
}
// 写方法
public void ti() {
// 使用了成员内部类
Innter08 innter08 = new Innter08();
innter08.say();
}
}
- 作用域:在外部类里面
- 成员内部类—访问—外部类成员—直接访问
- 外部类—访问—成员内部类—创建对象,再访问(使用相关方法)
- 外部其他类—访问成员内部类—2种方式
public class l6 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.ti();
// 外部内部类访问成员内部类3种方式
// 1.outer08.new Innter08();相当于把new Innter08()当成outer08的成员
Outer08.Innter08 innter08 = outer08.new Innter08();
innter08.say();
// 2.写一个方法在外部类中,可以返回Innter08对象
Outer08.Innter08 innter08Instance = outer08.getInner08Instance();
innter08Instance.say();
}
}
class Outer08 {// 外部类
private int n1 = 10;
public String name = "凌不疑";
protected class Innter08 {// 1.成员内部类(即不再方法中也不在代码块中,在成员的位置上写)
// 2.可以添加任意修饰符(public,protected,默认,private),因为他本身地位就是成员
public double sal = 9.9;
public void say() {
System.out.println("Outer的n1=" + n1 + "Outer的name=" + name);
}
}
// 方法,返回一个Innter08实例
public Innter08 getInner08Instance() {
return new Innter08();
}
// 写方法
public void ti() {
// 使用了成员内部类
// 创建成员内部类对象,然后使用相关的方法
Innter08 innter08 = new Innter08();
innter08.say();
System.out.println(innter08.sal);
}
}
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
静态内部类
- 静态内部类定义:定义在外部类的成员位置,并且有static修饰(StaticlnnerClass)
- 静态内部类可以直接访问外部类的所有静态成员,包括私有,但是不能直接访问非静态成员
- 可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
- 作用域:同其他成员,为整个类体
public class l6 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.show();
}
}
class Outer10 {// 外部类
private int n1 = 10;
private static String name = "袁善良";
// Inner10静态内部类
// 1.放在外部类成员位置
// 2.使用static修饰
// 3.可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员name
// 4.可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
static class Inner10 {
public void say() {
System.out.println(name);
}
}
public void show() {
Inner10 inner10 = new Inner10();
inner10.say();
}
}
- 成员内部类—访问—外部类成员—直接访问
- 外部类—访问—成员内部类—创建对象,再访问(使用相关方法)
- 外部其他类—访问—静态内部类3种方法
public class l6 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.show();
// 外部其他类 使用静态内部类
// 1.因为静态内部类可以通过类名直接访问,但是得通过访问权限
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
// 2.编写一个方法(非静态),可以返回静态内部类的对象实例
Outer10.Inner10 inner102 = outer10.getInner10();
inner102.say();
System.out.println("-----------");
// 静态,这没有再创建对象,直接用外部类名来用
Outer10.Inner10 inner103 = Outer10.getInner101();
inner103.say();
}
}
class Outer10 {// 外部类
private int n1 = 10;
private static String name = "袁善良";
// Inner10静态内部类
// 1.放在外部类成员位置
// 2.使用static修饰
// 3.可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员name
// 4.可以添加任意访问修饰符(public,protected,默认,private),其本身地位是成员
static class Inner10 {
public void say() {
System.out.println(name);
}
}
public void show() {
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
public static Inner10 getInner101() {
return new Inner10();
}
}
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则。如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
课堂测试题
写出输出结果:
class Test {// 外部类
public Test() {// 构造器
Innter s1 = new Innter();
s1.a = 10;
Innter s2 = new Innter();
System.out.println(s2.a);
}
class Innter {// 内部类。成员内部类
public int a = 5;
}
public static void main(String[] args) {
Test t = new Test();
Innter r = t.new Innter();
System.out.println(r.a);
}
}