基本介绍
一个类的内部又完整的嵌套了另一个类机构。被嵌套的类称为内部类(inner class),嵌套的其他类的类称为外部类(outer class)。是我们类的第五大成员【属性、方法、构造器、代码块、内部类】。内部类最大的特点就是可以直接访问私有属性,并且可以体现类和类之间的包含关系。
如果定义在局部位置(方法/代码块中):
(1)局部内部类(有类名)
(2)匿名内部类(没有类名)
定义在成员位置:
(1)成员内部类(没用static修饰)
(2)静态内部类(使用static修饰)
基本语法
class Outer{????????//外部类
? ? ? ? class inner{????????//内部类
????????}
}
class Other{????????//外部其他类
}
public class Demo01 {
public static void main(String[] args) {
}
}
class Outher{ //外部类
private int a=3;//成员一:属性
public Outher(int a){
this.a=a; //成员二:构造器
}
{
System.out.println("代码块");//成员三:代码块
}
public void m1(){
System.out.println("方法");//成员四:方法
}
class inner{ //成员五:内部类
}
}
局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
- 可以直接访问外部类的所有成员,包含私有的。
- 不能添加访问修饰符,因为它的地位是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final(但是加了final后不能被继承)。
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类--访问---》外部类的成员(直接访问即可)
- 外部类--访问--》局部内部类的成员(创建对象,再访问,但是要在作用域内)
- 局部内部类定义在方法中/代码块
- 作用域在方法体或代码块中
- 本质仍然是一个类
- 外部其他类--不能访问--》局部内部类(因为局部内部类是一个局部变量)。
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问。
public class Demo01 {
public static void main(String[] args) {
Outher outher = new Outher(5);
outher.m1();
System.out.println("outher的hashcode="+outher);
}
}
class Outher{ //外部类
private int a;//属性
public Outher(int a){
this.a=a; //构造器
}
private void m2(){
System.out.println("方法m2");
}
public void m1(){
//1.局部内部类时定义在外部类的局部位置,通常在方法
//3.不能添加访问修饰符,但是可以使用final修饰(不能被继承)
//4.作用域:仅仅在定义它的方法或代码块中
final class Inner{ //内部类(本质依旧是一个类)
public void m3(){
//2.可以直接访问外部类的所有成员,包括私有的。
//6.如果外部类和局部内部类成员重名,默认遵循就近原则,若想访问外部类的成员,使用(外部类名.this.成员)访问
int a=100;
System.out.println(a+"——>内部类的");
System.out.println(Outher.this.a+"——>外部类的");//Outher.this本质就是外部类的队象,及哪个对象调用了a
System.out.println("Outher.this hashcode="+Outher.this);
m2();
}
}
//5.外部类在方法中,可以直接创建内部类对象,然后调用方法即可。
Inner inner = new Inner();
inner.m3();
}
}
匿名内部类
- 本质是类。
- 内部类。
- 该类没有名字。
- 同时还是一个对象。
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名。
匿名内部类的基本语法
new 类或接口(参数列表){
?类体
};
public class Demo02 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
class Outer{//外部类
private int a=10;//属性
public void method(){//方法
//基于接口的匿名内部类
//需求:实现IA接口,并创建队象。
//一般是先用一个类实现接口,然后创建对象。编译类型是接口,运行类型是实现类。
// IA person=new Person();
// person.cry();
//可以使用匿名内部类实现简化开发,只使用一次实现类
//即编译类型依旧是接口,但此时运行类型变为了匿名内部类。
//匿名内部类只能使用一次。
//底层代码如下
/*
class Outer$1 implements IA{
@Override
public void cry(){
System.out.println("人在哭泣");
}
}
*/
//jdk 底层在创建匿名内部类Outher$1,立即就创建了Outher$1实例,把地址返给ia。
IA ia = new IA(){
@Override
public void cry(){
System.out.println("人在哭泣");
}
};
System.out.println("基于接口的匿名内部,类运行类型为:"+ia.getClass());//一般为外部类名+$1
ia.cry();
ia.cry();//ia是对象是可以反复使用的。
//基于类的匿名内部类
//此时father的编译类型为Father1类,运行类型为匿名内部类。
//底层创建匿名内部类Outer$2
/*
class Outer$2 extends Father1{
@override
public void cname(){
system.out.println("匿名内部类重写cname方法")
}
}
*/
//返回给father匿名内部类Outer$2对象
//("jack")参数列表会传递给 构造器。
Father1 father = new Father1("jack"){
@Override
public void cname(){
System.out.println("基于类的匿名内部类,匿名内部类重写cname方法");
}
};
System.out.println("运行类型为:"+father.getClass());//Outer$2
father.cname();
//基于抽象类的匿名内部类
Animal animal = new Animal(){//虽然抽象类不能用new实例化,但此时的new Animal()实际上是创建匿名内部类
@Override
public void eat(){
System.out.println("狗吃肉");
}
};
System.out.println("基于类的匿名内部类,运行类型为:"+animal.getClass());//Outer$3
animal.eat();
}
}
interface IA{//接口
public void cry();
}
//class Person implements IA{//接口实现类
// @Override
// public void cry(){
// System.out.println("人在哭泣");
// }
//}
class Father1{
public Father1(String name){
System.out.println("父亲的名字:"+name);
}
public void cname(){
}
}
abstract class Animal{
abstract void eat();
}
?
- 匿名内部类的语法比较奇特,因为匿名内部类即是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对上面代码可以看出这一特点,因此也可以调用匿名内部类方法。
- 可以直接访问外部类的所有成员,包含私有的。
- 不能添加访问修饰符,因为它的地位就是一个局部变量。
- 作用域:仅仅在定义它的方法或代码块中。
- 匿名内部类——访问——外部类成员(直接访问即可)。
- 外部其他类——不能访问——匿名内部类(因为匿名内部类地位是一个局部变量)。
- 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)访问。
public class Demo03 {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.f1();
}
}
class Outer01{
private int a=3;
public void f1(){
//不能添加访问修饰符,但是可以使用final修饰(不能被继承)
//作用域:仅仅在定义它的方法或代码块中
final Son son=new Son(){
int a=5;
//可以直接访问外部类的所有成员,包括私有的
//如果外部类和局部内部类成员重名,默认遵循就近原则,若想访问外部类的成员,使用(外部类名.this.成员)访问
@Override
public void hi() {
System.out.println("动态绑定的匿名内部类重写hi()方法 "+a);
}
@Override
public void run(String name) {
System.out.println("动态绑定的匿名内部类重写hi()方法 "+name+" "+Outer01.this.a);
}
};
son.hi();//动态绑定机制,编译类型为Son 运行类型为匿名内部类Outer01$1
son.run("jack");
//也可以直接调用,匿名内部类本身也是返回对象
new Son(){
int a=66;
@Override
public void hi() {
System.out.println("匿名内部类重写hi()方法 ");
}
@Override
public void run(String name) {
System.out.println("匿名内部类重写hi()方法 "+name);
}
}.run("jack");
}
}
class Son{
public void hi(){
System.out.println("Son hi()");
}
public void run(String name){
System.out.println(name+"在跑步");
}
}
当做实参直接传递,简洁高效。
public class Demo04 {
public static void main(String[] args) {
//当作实参传递,简洁高效,但是只能使用一次匿名内部类。
f1(new IL() {
@Override
public void say() {
System.out.println("此时的匿名内部类就是被当作实参");
}
});
//传统方法 这种方法可以多次调用,但是比较繁琐。
LI li = new LI();
f1(li);
}
public static void f1(IL il){
il.say();
}
}
interface IL{
public void say();
}
class LI implements IL{
@Override
public void say(){
System.out.println("传统方法");
}
}
成员内部类
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
public class Demo05 {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.h1();//调用成员内部类,可以先在方法中实例化内部类,然后调用方法。
outer02.new Inner02().say();//也可直接调用匿名对象的方法。
}
}
class Outer02{
private int a=666;
class Inner02{
public void say(){
System.out.println("a="+a);
}
}
public void h1(){
Inner02 inner02 = new Inner02();
inner02.say();
}
}
- ?可以直接访问外部类的成员位置,包含私有的。
- 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
- 作用域和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。
- 成员内部类——访问——外部类成员(直接访问)。
- 外部类——访问——成员内部类(要先创建对象,再访问)因为内部类在外部类里,可以访问成员内部类私有属性。
- 外部其他类——访问——成员内部类(如下代码)
- 如果外部类和成员内部类的成员重名时,成员内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)访问。
public class Demo05 {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.h1();//调用成员内部类,可以先在方法中实例化内部类,然后调用方法。
outer02.new Inner02().say();//也可直接调用匿名对象的方法。
//第一种方法:
Outer02.Inner02 inner02 = outer02.new Inner02();
inner02.say();
//第二种方法:
Outer02.Inner02 inner = outer02.getInner02();
inner.say();
}
}
class Outer02{
private int a=666;
class Inner02{
int a=888;
public void say(){
System.out.println("内部类a="+a+" 外部类a="+Outer02.this.a);
}
}
public void h1(){
Inner02 inner02 = new Inner02();
inner02.say();
}
public Inner02 getInner02(){
return new Inner02();
}
}
静态内部类
说明:静态内部类是定义在外部类的成员位置,并且有static修饰。
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员。
- 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
- 作用域:同其他成员,为整个类体。
- 静态内部类——访问——外部类(直接访问静态成员)。
- 外部类——访问——静态内部类(先创建对象,在访问)。
- 外部其他类——访问——静态内部类(如下代码块)
- 如果外部类和静态内部类的成员重名时,静态内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)访问。
public class Demo06 {
public static void main(String[] args) {
Outer03 outer03 = new Outer03();
outer03.h1();
//方式一:
//因为是静态内部类,可以通过类名直接访问(前提要满足访问权限)
Outer03.Inner03 inner03 = new Outer03.Inner03();
inner03.say();
//方式二:
//编写一个方法,可以返回静态的对象实例
Outer03.Inner03 inner = outer03.getInner();
inner.say();
}
}
class Outer03{
private int a=333;
private static String name="jack";
private static int m=222;
static class Inner03{
public void say(){
int m=666;
//System.out.println(a); //因为是静态内部类,static修饰,所以调用外部类成员只能调用静态成员,不能直接访问非静态成员。
System.out.println(name);
System.out.println("内部类m="+m);
System.out.println("外部类m="+Outer03.m);
}
}
public static void h1(){
Inner03 inner03 = new Inner03();
inner03.say();
}
public static Inner03 getInner(){
return new Inner03();
}
}
?
|