内部类
1.内部类概述
在类中定义类,叫内部类
2.内部类访问特点
1) 内部类可以直接访问外部类的成员,包括私有。
2) 外部类要访问内部类的成员,必须创建对象。
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner();
//Inner如同外部类的成员
3.成员内部类私有使用
成员内部类被私有,如同成员私有,在外部(本类外) 不能直接创建内部类对象了,需在本类创建公共访问方式
-
. class Demo2_InnerClass {
-
. public static void main(String[] args) {
-
Outer o = new Outer(); //通过外部类对象调用
-
o.print();
-
. }
-
. }
-
.
-
. class Outer {
-
. private int num = 10;
-
. private class Inner { //如同成员私有,在外部(本类外) 不能直接创建内部类对象了,需在本类创建公共访问方式
-
. public void method() {
-
. System.out.println(num);
-
. }
-
. }
-
.
-
. public void print() {
-
. Inner i = new Inner();
-
. i.method();
-
. //本类中访问,提供一个公共的访问方式,
-
}
-
. }
4.静态成员内部类
1) 被static修饰的成员内部类 static class Inner
2) 成员内部类被静态修饰后的访问方式是:
外部类名.内部类名 对象名 = 外部类名.内部类对象;
Outer.Inner oi = new Outer.Inner(); //Outer.new Inner,书写习惯是把new放在前面
Outer.Inner2.print();//静态内部类,静态方法一路点就行了
案例:
-
. class Demo1_InnerClass {
-
. public static void main(String[] args) {
-
. //外部类名.内部类名 对象名 = 外部类名.内部类对象;
-
. Outer.Inner oi = new Outer.Inner();
-
. oi.method();
-
. Outer.Inner2.print();//静态内部类,静态方法一路点就行了
-
. }
-
. }
-
. class Outer {
-
. static class Inner {//静态的内部类,看成静态的成员
-
. public void method() {//类里面有个非静态的方法,需创建对象去看
-
. System.out.println("method");
-
. }
-
. }
-
.
-
. static class Inner2 {
-
. public static void print() {
-
. System.out.println("print");
-
. }
-
. }
-
. }
5.成员内部类案例
要求:使用已知的变量,在控制台输出30,20,10。
-
. class Outer {
-
. public int num = 10;
-
. class Inner {
-
. public int num = 20;
-
. public void show() {
-
. int num = 30;
-
. System.out.println(?);//就近原则直接给num即可
-
. System.out.println(??);//20属于内部类的成员变量所以this.num
-
. System.out.println(???);//Outer.this.num,内部类之所以能够访问外部类成员,因为它获取了外部类的引用Outer.this//Outer下面的this成员变量
-
. }
-
. }
-
. }
-
. class InnerClassTest {
-
. public static void main(String[] args) {
-
. Outer.Inner oi = new Outer().new Inner();
-
. oi.show();
-
. }
-
. }
6.局部内部类访问局部变量
局部内部类,在方法中定义的内部类
局部内部类访问局部变量必须用final修饰
但是jdk1.8取消了这个事情,所以我认为这是个bug
案例:
-
. class Demo1_InnerClass {
-
. public static void main(String[] args) {
-
. Outer o = new Outer(); //内部类在外部类中创建了对象
-
. o.method();
-
//有名内部类在外部类成员方法中创建了对象(相当于提供访问方式),然后在主方法中,通过外部类对象调用访问方式,再调用内部类里的方法
-
. }
-
. }
-
. //局部内部类
-
. class Outer {
-
. public void method() {
-
. final int num = 10;
-
. class Inner {//局部内部类和局部变量一样,只在方法中有效,出了方法就无效了
-
. public void print() {
-
. System.out.println(num);
-
. }
-
. }
-
.
-
. Inner i = new Inner(); //在外部类中创建对象
-
. i.print();
-
. }
-
.
-
. /*public void run() {
-
. Inner i = new Inner(); //局部内部类只能在所在的方法中访问
-
. i.print();
-
. }*/
-
. }
说明:Final在类加载的时候,会进方法区中的常量池,常量池属于方法区的一部分.作用延长num的声明周期
7.匿名内部类
匿名内部类就是内部类的简化写法。
1) 前提
存在一个类或者接口:这里的类可以是具体类也可以是抽象类。没有名字类,需要想办法去表示它,去实现一个接口或继承一个类,去和外面的某个类或某个借口与其发生关系.
匿名内部类是局部内部类的一种,所以必须写在方法里.
2) 格式
new 类名或者接口名(){ //继承类,或实现接口
重写方法;
}
3) 本质
是一个继承了该类或者实现了该接口的子类匿名对象。
4)应用场景:
当对成员方法仅调用一次时候时
可以作为实际参数进行传递.
编译后生成Outer$1.class文件
-
class bj10_13 {
-
public static void main(String[] args) {
-
Outer o = new Outer();
-
o.method();
-
//匿名内部类,直接通过外部类对象,调用方法,在调用匿名内部类的重写方法实现接口
-
}
-
}
-
-
interface Inter { //接口
-
public void print();//抽象方法
-
}
-
-
class Outer {
-
public void method() {
-
//new 接口名(){重写方法} 叫匿名内部类实现接口—子类
-
//new 类名(){重写方法} 叫匿名内部类继承类—子类
-
new Inter() { //匿名内部类实现inter接口,实现接口要重写方法
-
public void print() { //必须重写抽象方法
-
System.out.println("print");
-
}
-
}.print();
-
// new 接口名(){重写方法} 整个代表inter的子类对象,再调用子类对象的print方法
-
//把重写实现和重写的步棸,包括创建对象都写在一起了,整个代表inter的子类对象
-
}
-
}
-
}
8.匿名内部类重写多个方法调用
-
class bj10_14 {
-
public static void main(String[] args) {
-
Outer o = new Outer();
-
o.method();
-
System.out.println("Hello World!");
-
}
-
}
-
interface Inter { //接口
-
public void show1(); //抽象方法
-
public void show2();
-
}
-
class Outer { //外部类
-
public void method() { //方法
-
/*new Inter() { //匿名内部类(实现接口,就要重写方法有几个重写几个)
-
public void show1() { //重写方法
-
System.out.println("show1");
-
}
-
public void show2() { //重写方法
-
System.out.println("show2");
-
}
-
}.show1();//实现一个方法对其调用还比较好,再调用show2时,这个对象就得再创建一次.
-
//建议匿名内部类只针对重写一个方法的时候使用
-
//要是多个方法的时候就要用有名字的类了
-
*/
-
//改进
-
Inter i = new Inter() { //父类引用指向子类对象
-
public void show1() { //重写方法
-
System.out.println("show1");
-
}
-
public void show2() { //重写方法
-
System.out.println("show2");
-
}
-
i.show1();
-
i.show2();//编译时看接口中的show2方法,运行时是子类对象中的show2方法.因此可以实现多个方法.
-
}
-
}
-
//当子类中有自己特有的方法时:
-
/*public void show3() {
-
System.out.println("show3");
-
}
-
i.show3();……多态
-
*/
-
//有个弊端,当对象里有自己的方法时是无法调用的//编译不通过
-
//匿名内部类是不能向下转型的,向下强转得有子类类名,这个没有.
9.匿名内部类在开发中的应用---当做参数传递
-
class bj10_15 {
-
public static void main(String[] args) {
-
PersonDemo pd = new PersonDemo ();
-
//用有名字的子类做,匿名对象赋值给父类引用
-
pd.method(new Student());
-
//其中new Student()是有名字的子类对象
-
//把new Student()赋值给Person p父类引用指向子类对象(传person的子类对象)(多态的特性,可以父类引用指向子类对象,即可以将子类对象赋值给父类引用)
-
//method里面的p.show,编译的时候看的是Person里的show方法,运行的是看的Student里面的show方法
-
//匿名内部类 赋值给父类引用
-
//匿名内部类在开发中的应用当做参数传递,本质把匿名内部类看做一个对象.
-
//method(里面是person类型),下面整个括号里是person的子类对象
-
//new Person(){}继承Person类,里面要重写Person的抽象方法
-
-
pd.method(new Person(){
-
public void show() {
-
System.out.println("show1");//继承类要重写抽象方法
-
}
-
});
-
-
}
-
}
-
abstract class Person {//抽象类,不能不实例化(不能new),传一个person子类对象
-
public abstract void show();
-
}
-
class Student extends Person {//继承了Person,相当于他的子类//有名字的类
-
public void show() {
-
System.out.println("show");
-
}
-
}
-
class PersonDemo {
-
public void method(Person p) { //要传一个person类型的引用 p.show();
-
}
-
}
10匿名内部类案例
//链式编程,每次调用方法之后还能调用方法,证明调用方法返回的是对象
//要求在控制台输出"HelloWorld"
-
class bj10_16 {
-
public static void main(String[] args) {
-
Outer.method().show();
-
}
-
}
-
interface Inter {
-
void show();
-
}
-
-
class Outer {
-
//补齐代码 //从主方法中开始分析
-
下面是答案
-
public static Inter method() {
-
//返回类型是Inter,返回Inter子类对象就可以
-
//但是inter是个借口,调用show方法没有意义,
-
return new Inter() {
-
public void show() {
-
System.out.println("HelloWorld");
-
}
-
};
-
}
-
}
思考过程:
1. //补齐代码 //从主方法中开始分析Outer.method().show();
2.用类名.调用方法,说明method这个方法是静态的,返回值类型不确定
3.非静态的一定要创建对象才能调用,调用完method后还能调用.show,说明method调用完后返回的是一个对象
4.show方法只有在Inter中,因此method返回值类型是Inter.
5.Inter i = Outer.method();//Outer.method 返回的是Inter类型的对象,因此用Inter接收
6.new Inter(){}.show子类对象调用自己里面的show方法,其实是父类引用指向子类对象.i.show()编译看Inter接口里面的show方法,运行看子类重写的show方法