首页 > 代码库 > 内部类
内部类
内部类
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) 本质
是一个继承了该类或者实现了该接口的子类匿名对象。
- 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方法
内部类