内部类作用:
1.打破Java单继承的限制
2.在内部类中做更多的功能,为外部类服务
3.可以资源的隐藏
一.成员内部类
定义格式:
class 外部类 { 修饰符 class 内部类 { } }
成员内部类又分为静态内部类和非静态内部类
1. 静态内部类 特点: 1.静态内部类可以访问外部类的静态属性和静态方法 2.外部类能否使用内部类的资源? 如果是静态资源,可以直接通过内部类名.资源名 如果是非静态资源,那么需要通过内部类的对象.资源名 语法结构: class 外部类名{ //定义内部类 [权限修饰符4种] static [final] class 类名{ } } 2. 非静态内部类 特点: 1.非静态内部类可以直接使用外部类所有资源 2.外部类使用内部类的资源,首先创建非静态内部类的对象,然后才能使用内部类中的资源 3.如果是内部类中的静态常量,外部类可以直接使用 4.外部类的静态方法,不能使用内部类资源 5.非静态内部类中不能存在静态的方法和静态的属性,但是可以存在静态的常量 语法结构: [权限修饰符] class 类名{ }
访问方式:
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类,前提是必须存在一个外部类对象。 外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
代码:
package com.atguigu.day13; public class Demo1 { public static void main(String[] args) { //创建内部类对象 Body.heart s=new Body().new heart(); s.show(); Body b=new Body(); b.getheart(); } } class Body{ int num=1; static String name="lin2"; class heart{ int num=2; final static String addr="China"; public void show(){ int num=3; System.out.println("我是内部类中的方法"); //访问外部类中的成员变量 1 System.out.println(Body.this.num); //访问外部类中的成员方法 Body.this.m1(); //访问内部类中的成员变量 2 System.out.println(this.num); //访问内部类中的方法中的变量 3 System.out.println(num); //访问外部类的静态方法 Body.m2(); } } static class heart2{ static void show2(){ System.out.println("我是静态内部类的静态方法"); //访问外部类中的静态资源 System.out.println(Body.name); Body.m2(); } } //提供一个访问内部类的方法 public void getheart(){ heart h=new heart(); h.show(); } public void m1(){ System.out.println("我是外部类方法"); } public static void m2(){ System.out.println("我是外部类静态方法"); } }
二.局部内部类
局部内部类,是定义在外部类方法中的局部位置,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
注意:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的
package com.atguigu.day13; /* 注意: 1.局部内部类只能被default修饰 2.局部内部类可以被final/abstract修饰 3.局部内部类使用外部类的资源要看外部类的方法静态还是非静态 方法为非静态,可以直接使用外部类静态或非静态的资源 方法为静态,可以直接使用外部类中静态的资源 4.局部内部类编译成功后也会产生对应的字节码文件 外部类的名字$局部内部类的名字 Demo2.Inner.class 5.局部内部类中不能存在静态的属性但是可以存在静态的常量 6.在方法内创建内部类对象,通过内部类对象调用内部类中的方法 7.当局部内部类的外面的方法内使用局部变量时,那么变量前自动默认加final(jdk1.8) */ public class Demo2 { int age=30; static String name="lin1"; public static void main(String[] args) { Demo2 d2 = new Demo2(); d2.show(); Demo2.show2(); } public void show(){ int num=20; class Inner{ public void innerMethod(){ System.out.println(age); System.out.println(name); System.out.println("this is inner method"); } } Inner in1 = new Inner(); in1.innerMethod(); } public static void show2(){ class Inner2{ public void innerMethod2(){ System.out.println(name); } } } }
如何调用局部内部类
package com.atguigu.day13;
interface Run{
public void run();
}
public class Demo3 {
public static void main(String[] args) {
Demo3 d3= new Demo3();
Run r1 = d3.outMethod();
r1.run();
}
public Run outMethod(){
//当局部内部类的外面的方法内使用局部变量时,那么变量前自动默认加final(jdk1.8),也就是局部内部类只能访问被final修饰的局部变量
// 原因:内部类对象的生命周期会超过局部变量的生命期
// 局部变量的生命期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。
// 内部类对象生命期,与其它类一样,当创建一个局部内部类对象后,只有当没有其它人再引用它时,它才能死亡。
// 所以完全可能一个方法已调用结束(局部变量已死亡),但该局部类的对象仍然活着。即:局部类的对象生命期会超过局部变量
int num=20;
class Inner implements Run{
@Override
public void run() {
System.out.println("just inner run method\t"+num);
}
}
return new Inner();
}
}
三.匿名内部类
作用:匿名内部类是创建某个类型子类对象的便捷方式。(匿名内部类适合用于创建那种只需要一次使用的类)
package com.atguigu.day13; import org.junit.Test; import org.junit.runners.Parameterized; import java.util.Collection; /* 匿名内部类:没有名字的类 匿名对象:没有名字的对象 方式1: new fu(){ 重写父类的方法 } 创建了一个子类,但是子类没有名字 方式2: new fu(实参列表){ 重写父类的方法 } 创建了一个子类,但是子类没有名字 方式3: new fu接口(){ 重写接口中的方法 } 创建了一个子类,但是子类没有名字 注意: 1.匿名内部类也会生成独立的字节码文件 外部类的名字$序号.class 2.内名内部类不可以存在静态的变量,但可以存在静态的常量 */ public class Demo4 { @Test public void test01(){ new Fu(){ @Override public void show() { System.out.println("this is inner show"); } }; } @Test public void test02(){ new Fu(10){ @Override public void show() { System.out.println("this is inner show(10)"); } }; } @Test public void test03(){ new Run2(){ @Override public void run(){ System.out.println("just run"); } }; } @Test public void test04(){ new Animal2(){ @Override public void eat(){ System.out.println("just eat"); } }; } } class Fu{ int num; public Fu() { } public Fu(int num) { this.num = num; } public void show(){ System.out.println("this is fater show"); } } interface Run2{ void run(); } abstract class Animal2{ abstract void eat(); }
匿名内部类的使用
package com.atguigu.day13; import org.junit.Test; //使用匿名内部类 /* 1.在完成内部类的声明的时候就已经创建了内部类的对象 2.匿名内部类创建的是子类对象可以使用子类,可以使用子类重写父类的方法 已经从父类继承的资源 3.可以使用接口或者抽象类作为形参 */ public class Demo5 { @Test public void test1(){ new Fu2(){ @Override public void test1() { System.out.println("this is noname inner test"); } }.test1();//this is noname inner test } @Test public void test2(){ Fu2 f2=new Fu2(20){ @Override public void test1() { System.out.println("this is noname inner test1"); } }; f2.test1();//this is noname inner test1 f2.show();//this is show } @Test public void test3(){ Fly fly = new Fly() { @Override public void fly() { System.out.println("just fly"); } }; fly.fly();//just fly } public static void method1(Fly fly){ fly.fly(); } @Test public void test4(){ Bird bird = new Bird(); method1(bird);//bird fly method1(new Fly() { @Override public void fly() { System.out.println("some one fly"); } //some one fly }); } } class Fu2{ int num; public Fu2() { } public Fu2(int num) { this.num = num; } public void test1(){ System.out.println("this is test1"); } public void show(){ System.out.println("this is show"); } } interface Fly{ void fly(); } class Bird implements Fly{ @Override public void fly() { System.out.println("bird fly"); } }
练习1:
package com.atguigu.day13; import java.util.Arrays; import java.util.Comparator; public class Demo6 { public static void main(String[] args) { Students s1=new Students("lin1",23,310.0); Students s2=new Students("lin2",22,301.0); Students s3=new Students("lin3",31,305.0); Students s4=new Students("lin4",27,302.0); Students s5=new Students("lin5",30,311.0); Students[] arr1= {s1,s2,s3,s4,s5}; System.out.println("-------------before sort----------------"); for (int i = 0; i <arr1.length ; i++) { System.out.println(arr1[i].toString()); } Arrays.sort(arr1, new Comparator() { @Override public int compare(Object o1, Object o2) { Students s1=(Students) o1; Students s2=(Students) o2; return Double.compare(s1.getScore(),s2.getScore()); } }); System.out.println("-------------after sort----------------"); for (int i = 0; i <arr1.length ; i++) { System.out.println(arr1[i].toString()); } } }
package com.atguigu.day13; public class Students { String name; int age; Double score; public Students() { } public Students(String name, int age, Double score) { this.name = name; this.age = age; this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Double getScore() { return score; } public void setScore(Double score) { this.score = score; } @Override public String toString() { return "Students{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}'; } }
输出:
-------------before sort---------------- Students{name='lin1', age=23, score=310.0} Students{name='lin2', age=22, score=301.0} Students{name='lin3', age=31, score=305.0} Students{name='lin4', age=27, score=302.0} Students{name='lin5', age=30, score=311.0} -------------after sort---------------- Students{name='lin2', age=22, score=301.0} Students{name='lin4', age=27, score=302.0} Students{name='lin3', age=31, score=305.0} Students{name='lin1', age=23, score=310.0} Students{name='lin5', age=30, score=311.0}