目录
成员内部类
假设,现在我定义了一个Computer类,来描述一台计算机。对于一台计算机而言,最最核心的部分莫过于CPU了。而对于CPU而言,也只有计算机这个类才会包含CPU。对于其他所有类而言,应该是不会直按用到的。
我们希望,既然CPU这个类,只能被计算机使用,从代码的角度我们就合望,CPU能被Computer类访问到
public class Demo1 {
public static void main(String[] args) {
//正常CPU类可以被每一个类创建cpu对象,但是只希望被Computer类访问
//定义在类内部就可以了
Cpu cpu = new Cpu();
}
}
class Computer {
Cpu cpu;
class Cpu {
int coreNum;
int requency;
}
}
/*
class Cpu{
int coreNum;
int requency;
}*/
在Java语言中类可以嵌套定义
内部类:定义在其他类内部的类就称为内部类
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有。外部类要访问内部类的成员,必须创建对象。
成员位置内部类:
约定:把包含内部类的类,称之为外部类
内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有。
2.外部类要访问内部类的成员,必须创建对象。
如何理解成员位置内部类?
成员位置内部类定义在外部类的成员位置,将内部类看成一个整体,就类比于成员变量或成员方法的一个普通成员。
内部类依赖于外部类对象而存在。而static不依赖于对象而存在
内部类的访问(外部类的外部):
1.在外部类的外部,访问内部类,创建内部类对象
外部类名.内部类名 对象名 = 外部类对象.内部类对象; (代码有两种方式)
public static void main(String[] args) {
MemberOuter memberOuter = new MemberOuter();
memberOuter.accessInner();
//创建其他类内部定义的普通成员位置,内部类对象 第一种方式
MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
memberInner.accessOuter();
//第二种方式
MemberOuter.MemberInner memberInner1 = new MemberOuter().new MemberInner();
memberInner.accessOuter();
}
2.静态成员位置内部类,作为外部类的一个静态成员,不在依赖于外部类对象而存在 外部类.内部类 对象名 = new 外部类.内部类();
public static void main(String[] args) {
MemberOuter.staticMemberInner staticMemberInner = new MemberOuter.staticMemberInner();
staticMemberInner.accessOuter();
}
静态上下文问题:在外部类的静态方法中,访问成员位置内部类
//在外部类的静态方法中,访问成员位置内部类
public static void accessInnerInStatic() {
//new MemberInner();//静态上下文问题 可以用外部类对象this:this.new MemberInner();
//MemberInner memberInner = this.new MemberInner();但是this没有当前对象,因为是static
//但是我们可以自己创建一个外部类对象,在外部类对象上,创建内部类对象
MemberOuter memberOuter = new MemberOuter();
MemberInner memberInner = memberOuter.new MemberInner();
}
完整代码
package com.wolf.inner.basic;
/**
* @create 2021-07-26 20:27
*/
public class Demo1 {
public static void main(String[] args) {
MemberOuter memberOuter = new MemberOuter();
memberOuter.accessInner();
//创建其他类内部定义的普通成员位置,内部类对象 第一种方式
MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
memberInner.accessOuter();
//第二种方式
MemberOuter.MemberInner memberInner1 = new MemberOuter().new MemberInner();
memberInner.accessOuter();
MemberOuter.staticMemberInner staticMemberInner = new MemberOuter.staticMemberInner();
staticMemberInner.accessOuter();
}
}
class MemberOuter {
private int outerI;
private static int staticI;
private void outerPrivateMethod() {
System.out.println("outer private");
}
//在外部类中创建内部类对象
public void accessInner() {
MemberInner memberInner = new MemberInner();
System.out.println(memberInner.innerI);
memberInner.innerMemberMethod();
}
/* 如何理解成员位置内部类?
成员位置内部类定义在外部类的成员位置,将内部类看成一个整体,就类比于成员变量或成员方法的一个普通成员。
内部类依赖于外部类对象而存在。而static不依赖于对象而存在*/
//在外部类的静态方法中,访问成员位置内部类
public static void accessInnerInStatic() {
//new MemberInner();//静态上下文问题 可以用外部类对象this:this.new MemberInner();
//MemberInner memberInner = this.new MemberInner();但是this没有当前对象,因为是static
//但是我们可以自己创建一个外部类对象
MemberOuter memberOuter = new MemberOuter();
MemberInner memberInner = memberOuter.new MemberInner();
}
//成员位置内部类
//private 不能直接访问
class MemberInner {
int innerI = 1;
public void innerMemberMethod() {
System.out.println("inner method");
}
public void accessOuter() {
System.out.println(outerI);
outerPrivateMethod();
}
}
//静态内部类
static class staticMemberInner {
//外部类的静态上下文(静态内部类)中的方法也是静态上下文,无法直接访问外部类的非静态的成员变量和成员方法
public void accessOuter() {
//System.out.println(outerI);
//outerPrivateMethod();
System.out.println(staticI);
accessInnerInStatic();
}
}
}
练习与补充
//在控制台分别输出10,20,30
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println( ?);
System.out.println( ??);
System.out.println( ???);
}
}
}
答案
System.out.println(Outer.this.num);//外部类当前对象成员变量值
//System.out.println(new Outer().num);//不推荐
System.out.println(this.num);
//System.out.println(Inner.this.num); //等同可省略
System.out.println(num);
/*
在静态中this对象和static是冲突的,但是在内部类中 类名.this this仅仅指的是从哪个类嵌套的当前对象,和static没有关系*/
局部内部类
定义在其他类的方法体内部的类;
访问特征:1.只能在定义该类的方法体中访问该类
package com.wolf.inner.basic.localinner;
/**
* @create 2021-07-27 10:04
*/
public class Demo1 {
}
class LocalOuter {
private int privateI;
private void privateMethod() {
//new LocalInner();错误
}
public void local() {
//定义一个局部内部类
class LocalInner {
int inner;
public void access() {
//在局部内部类中,直接访问外部类私有成员
System.out.println(privateI);
privateMethod();
}
}
//只能在定义该类的方法体中访问该类
LocalInner localInner = new LocalInner();
System.out.println(localInner.inner);
localInner.access();
}
}
2.可以访问方法体中局部变量,但该局部变量必须被 final 修饰;生命周期冲突
生命周期的冲突 局部内部类对象 vs 局部变量
1.局部变量的生命周期、随着方法的执行结束,即栈帧销毁,而从内存中消失
2.但是对于局部内部类对象而言,存储在堆上,对象的销毁和方法栈帧,没有直接关系简单来说,就是方法运行完,局部变最不存在了,但是对象还在
3.所以,如果方法运行完毕之后,还有人可以使用这个对象,那么就可以通过该局部内部类对象去访问这个局部变量,而此时,局部变量早已随着方法的执行完毕,而从内存中消失
匿名内部类
匿名内部类的前提:存在一个类(可以是抽象类,可以是具体类)或者接口
匿名内部类(通常是以局部内部类)对象格式:
new 类名或者接口名( ) { 重写方法; }
本质:是(一个继承了类或者实现了接口的(匿名)子类)匿名对象
package com.wolf.inner.anonymouus;
/**
* @create 2021-07-27 10:54
* day14 - 5 整齐及注释
*/
public class Demo {
public static void main(String[] args) {
//匿名对象
//没有引用对象,使用一次就用不了了
new MyClass().show();
//1、(接口)同样的工作,利用匿名内部类一次完成
new MyInterface() {
//既定义了对象,又创建了该匿名内部类的一个对象
@Override
public void show() {
System.out.println("内部类对象 show");
}//在代码块中,所以是局部位置内部类
}.show();
//2、利用匿名内部类对象,创建一个MyOuter类,子类对象
MyOuter myOuter = new MyOuter(1) {
public void accessFather() {
System.out.println(i);
test();
}
@Override
public void test() {
System.out.println("匿名 test");
System.out.println(i);
}
};
//多态
myOuter.test();
//myOuter.accessFather();//编译看左面,无法访问子类方法
//3、利用匿名内部类对象,创建抽象类的子类对象
new AbstractClass() {
@Override
public void show() {
System.out.println("匿名AbstractClass show");
}
}.show();
}
}
interface MyInterface {
void show();
}
class MyClass implements MyInterface {
@Override
public void show() {
System.out.println("MyInterface show");
}
}
class MyOuter {
int i = 100;
public MyOuter(int i) {
this.i = i;
}
public void test() {
System.out.println("MyOuter test");
}
}
//已经存在的抽象类
abstract class AbstractClass {
public abstract void show();
}
匿名内部类的使用
package com.wolf.inner.anonymouus;
/**
* @create 2021-07-27 14:55
*/
public class Demo2 {
public static void main(String[] args) {
//给匿名内部类起一个名字,用父类引用变量只想它
UseClass useClass =
//创建匿名内部类
new UseClass(){
@Override
public void method1() {
System.out.println("method1");
}
@Override
public void method2() {
System.out.println("method2");
}
public void method3(){
System.out.println("method3");
}
};//.method3();//只能访问一个方法,若要多次访问成员,故创建一个方法
//有局限:子类自定义方法不能访问,因为多态编译看左面
//useClass.method1();
//useClass.method2();
//useClass.method3();//访问不到
}
}
abstract class UseClass{
public abstract void method1();
public abstract void method2();
}
1.首先回顾我们曾经讲过的方法的形式参数是引用类型的情况
重点是接口的情况,我们知道这里需要一个子类对象。
而匿名内部类对象 就是一个子类匿名对象,所以,可以使用匿名内部类改进以前的做法。
2.方法返同值是接口类型的情况
package com.wolf.inner.anonymouus;
/**
* @create 2021-07-27 14:55
*/
public class Demo2 {
public static void main(String[] args) {
//创建匿名内部类
//一次或多次使用匿名内部类对象
useAnonymousInner();
//在开发中,只调用一次某方法,该方法接收的参数类型,接口类型
runMethod(new MyRunner() {
@Override
public void run() {
System.out.println("development use");
}
});
getRunner().run();
}
//因为return也是只运行一次
public static MyRunner getRunner() {
//作为方法接口类型的对象
return new MyRunner() {
@Override
public void run() {
System.out.println("return MyRunner");
}
};
}
public static void runMethod(MyRunner myRunner) {
myRunner.run();
}
private static void useAnonymousInner() {
//创建匿名内部类:通常在只使用一次类或接口的子类对象的情况下
new UseClass() {
@Override
public void method1() {
System.out.println("method1");
}
@Override
public void method2() {
System.out.println("method2");
}
public void method3() {
System.out.println("method3");
}
}.method3();//只能访问一个方法,不能访问多个,每次访问都需要创建一次匿名内部类对象
UseClass useClass = new UseClass() {
@Override
public void method1() {
System.out.println("method1");
}
@Override
public void method2() {
System.out.println("method2");
}
public void method3() {
System.out.println("method3");
}
};//只能访问一个方法,若要多次访问成员,故创建一个方法
//有局限:子类自定义方法不能访问,因为多态编译看左面
useClass.method1();
useClass.method2();
//useClass.method3();//访问不到
}
}
abstract class UseClass {
public abstract void method1();
public abstract void method2();
}
interface MyRunner {
void run();
}
练习
package com.wolf.inner.anonymouus;
/**
* @create 2021-07-27 15:47
* 要求在控制台输出 helloWorld 字符串
*/
public class Exercise {
public static void main(String[] args) {
Outer.method().show();
}
}
interface Inter {
void show();
}
class Outer {
//补全代码
}
答案
package com.wolf.inner.anonymouus;
/**
* @create 2021-07-27 15:47
* 要求在控制台输出 helloWorld 字符串
*/
public class Exercise {
public static void main(String[] args) {
Outer.method().show();
//分析: 类名.方法 的方法一定是静态方法 有返回值且一定是接口类型的子类对象
}
}
interface Inter {
void show();
}
class Outer {
//补全代码
//返回接口的子类对象
public static Inter method() {
return new Inter() {
@Override
public void show() {
System.out.println("helloWorld");
}
};
}
}