一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称之为内部类inner class,嵌套该内部类的类称为外部类。就像双重for循环,外部for循环里面包含着另一个内层循环。内部类是类的第5大成员,[属性,方法,构造器,代码块,内部类]
内部类的最大特点就是可以直接访问外部类的私有属性,且可以体现类与类之间的包含关系
成员内部类的基本语法演示:
class Outer{//外部类
class inner{//内部类
}
}
class other{}//其他类
代码演示:
public class Outer {//外部类
private int x = 21;
class inner{//内部类
public void innerMethod(){
System.out.println(x);//直接调用外部类的私有属性
}
}
}
class other{//其他类
}
内部类分为4种:分别在局部位置和成员位置,根据不同的修饰或命名有不同的叫法
public class other {//其他类
}
class outer{//外部类
public void m1(){
class inner{//局部内部类
}
}
}
局部内部类的特点
特点演示:
public class other {//其他类
public static void main(String[] args) {
new outer().m1();
}
}
class outer{//外部类
private int num = 21;
public void m1(){
final class inner{//局部内部类-2.无法访问修饰符,只能修饰final
private int num = 888;
public void m2inner(){
System.out.println(num);//1.局部内部类直接方法外部类的成员.4。如左
System.out.println("局部内部类的num"+num+"外部类的num"+outer.this.num);//7.外部类和内部类成员重名怎么区分调用
}
public int a = 1;
}
//5.外部类访问内部局部类的成员,需要创建内部局部类实例化对象。且需在作用域之内
new inner().m2inner();
}
//3,无法在局部内部类的作用域范围外创建
//new inner();
}
匿名内部类本质就是基于接口或者其他类,实现或者继承,然后创建一个新类,且实例化返回一个对象
匿名内部类存在的位置和局部内部类相同,都在外部类的方法中或者代码块中。
匿名内部类的特点
匿名内部类的语法
new 类或者接口(参数列表){
类体
};
举例说明及引出
在学习接口后,了解了各个实现了同一个接口的类,可以重写接口的方法。
比如现在有一个接口IA 他有一个抽象方法cry,老虎类实现了这个接口
外部类的m1方法中需要调用老虎类的cry方法
在未学习匿名内部类前应该是这样实现的
class outer{//外部类
public void m1(){
new tiger().cry();
}
}
interface IA{
void cry();
}
class tiger implements IA{
@Override
public void cry() {
System.out.println("老虎嗷嗷叫...");
}
}
但是因为就调用一次,但是还得去创建一个新类。有点浪费内存,所以可以使用匿名内部类实现。
语法解释:
public void m1(){
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎嗷嗷叫");
}
};
tiger.cry();
}
这一段就是在外部类的方法中使用了匿名内部类,在这一段代码中做了这么几件事:
class 匿名 implement IA{}
根据之前学到的知识,等号左边是编译类型,等号右边是运行类型。
根据上面的代码可以看到 编译类似是IA接口类型,但是运行类型却不能直接认为是IA接口。运行类型是底层创建的匿名内部类
因为这个匿名内部类,没有我们定义的类名。所以它只能使用一次,而我们将他实例化的对象地址给到了tiger。后面也无法再实例化一个对象了。所以说是匿名内部类只能使用一次,但是它已经实例化的对象,我们可以通过它的引用tiger,反复调用。
此致就解决了只需要使用一次还要创建一个类的问题。
完整代码:
public class other {//其他类
public static void main(String[] args) {
new outer().m1();
}
}
class outer{//外部类
public void m1(){
IA tiger = new IA() {//匿名内部类
@Override
public void cry() {
System.out.println("老虎嗷嗷叫");
}
};
tiger.cry();
tiger.cry();
tiger.cry();
}
}
interface IA{
void cry();
}
上面是基于接口举例的匿名内部类,下面用基于普通类的案例演示下
基于接口的匿名类,可以看作是匿名内部类实现了接口。那么基于普通类,可以看作是匿名内部类继承于普通类extends
public class other {//其他类
public static void main(String[] args) {
new outer().m1();
}
}
class outer{//外部类
public void m1(){
Father father = new Father(){//匿名内部类
};
}
}
class Father{
public Father() {
System.out.println("父类的构造器被调用");
}
}
通过运行后输出-父类的构造器被调用,这说明匿名内部类确实会和子类一样调用父类的构造器的。
匿名内部类的使用注意点
class outer{//外部类
public void m1(){
new Father(){
}.hi();//因为是定义和返回对象一体的,所以可以直接看作是临时对象,直接调用
}
}
class Father{
public Father() {
System.out.println("父类的构造器被调用");
}
public void hi(){
System.out.println("hi,");
}
}
其他特点和注意事项与局部内部类差不多
匿名内部类的实践
第一题
class outer{//外部类
public void test(IA ia){
ia.print();
}
public void m1(){
test(new IA() {//传入了一个匿名内部类
@Override
public void print() {
System.out.println("匿名内部类的print");
}
});
}
}
interface IA{
void print();
}
只是看起来理解性不太好,但是解决了只使用一次还要创建类的麻烦。

把这一部分看作是一个整体的参数就行
第二题
比较简单,直接上代码
public class testinners2 {
public static void main(String[] args) {
new CallPhone().AlarmClock(new Bell() {//临时对象调用ALarm方法,传入匿名对象(实现了Bell接口)
@Override
public void ring() {
System.out.println("快点起床");
}
});
new CallPhone().AlarmClock(new Bell() {
@Override
public void ring() {
System.out.println("再不起床,扣积分");
}
});
}
}
interface Bell{
void ring();
}
class CallPhone{
public void AlarmClock(Bell bell){
bell.ring();
}
}
成员内部类定义在外部类的成员位置,和属性 方法 构造器是同级别,且没有static修饰
成员内部类演示:
public class other {//外部其他类
public static void main(String[] args) {
//外部其他类访问成员内部类 方法一:直接创建
outer1 ou2 = new outer1();
outer1.Inner2 inner3 = ou2.new Inner2();
inner3.innerme();
//外部其他类访问成员内部类 方法二:使用外部类返回成员内部类的对象
outer1.Inner2 inner4 = ou2.getinner2();
inner4.innerme();
}
}
class outer1{
private int num = 90;
public class Inner2{//成员内部类
public void innerme(){
System.out.println(num);//直接使用外部类的成员
}
}
//外部类访问成员内部类
public Inner2 getinner2(){
Inner2 inner2 = new Inner2();
inner2.innerme();
return inner2;
}
}
注意点:外部类其他类访问成员内部类的方法:
第一种:先创建外部类的对象 outer1 ou2 = new outer1();
然后通过类名.成员内部类名作为编译类型 且使用外部类的对象去创建成员内部类的对象 outer1.Inner2 inner3 = ou2.new Inner2();
第二种:就是外部类直接将创建成员内部类封装在方法里,返回创建好的对象,给个引用即可。
静态内部类也是定义在外部类的成员位置上,但是与成员内部类的区别就是静态内部类加了static修饰
静态内部类演示:
public class other {//外部其他类
public static void main(String[] args) {
//外部其他类访问静态内部类 第一种:直接创建对象
outer1.Inner5 inner88 = new outer1.Inner5();
inner88.print1();
//外部其他类访问静态内部类 第二种:使用外部类封装返回的对象
outer1.Inner5 inner99 = outer1.getInner5();
inner99.print1();
}
}
class outer1{
private static int num = 90;
public static class Inner5{//静态内部类
private static int num = 88;
public void print1(){
System.out.println(num +" "+outer1.num);//直接调用和重名问题
}
}
public void m1(){
Inner5 inner5 = new Inner5();
inner5.print1();
}
public static Inner5 getInner5(){
return new Inner5();
}
}
注意点:静态内部类和成员内部类在外部其他类的调用语法稍有不同,且都要注意修饰符范围
静态内部类也是静态,需要遵守静态只能直接调用静态的规定。
重点:匿名内部类要理解透彻,它既是一个类的定义同时也是一个对象。
public class Test1 {
public Test1(){
inner s1 = new inner();
s1.a = 10;
inner s2 = new inner();
System.out.println(s2.a);
}
public static class inner{
public int a = 5;
}
public static void main(String[] args) {
Test1 t1 = new Test1();
inner s3 = new inner();
System.out.println(s3.a);
}
}
5
5