内部类
概念
所谓内部类就是在一个类的内部再申明一个类。
凡是申明在类的成员位置的就是成员内部类,凡是申明在方法或者代码块中的类都是局部内部类。
成员内部类
非静态成员内部类
基本写法
案例:
public class Outer {
private String name;
public void method() {
System.out.println("这是外部类的非静态成员方法");
};
public static void stMethod() {
System.out.println("外部内的静态成员方法");
}
public class Inner{
private int age;
public void innerMethod() {
System.out.println("内部类的非静态成员方法");
}
}
}
非静态成员内部类的对象创建。
如果要创建内部类的对象,则必须先有外部类对象。
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
Inner inner1 = new Outer().new Inner();
inner.innerMethod();
}
}
tips:
在非静态内部类中不能申明静态方法。 在非静态的内部类中不能申明静态的成员变量,但是可以申明常量。
内部类的一些特征
编译:所有的成员内部类都会被编译成一个独立的字节码文件,文件的名称为“外部类的类名$内部类类名.class”。 访问权限问题
成员的内部类可以使用任何访问修饰符,表现的状态和其他成员一样。
在内部类中可以访问外部类的所有成员 在非静态成员内部类中可以调用所有的外部类方法 在非静态成员内部类中使用外部类的this的时候,语法是:外部类类名.this。
静态成员内部类
案例:
public class Outter {
public static class Inner{
private String name;
public void method() {
System.out.println("内部类的非静态方法");
}
public static void stMethod() {
System.out.println("内部类的静态方法");
}
}
}
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
inner.method();
Outter.Inner.stMethod();
}
}
静态内部类中可以申明静态和非静态的方法和成员变量。
静态内部类中可以调用外部类的任何静态的成员变量和方法,但是不能调用任何非静态的方法和变量,更不能使用外部类的this对象。
局部内部类
申明在类的代码块中的类就是局部内部类。
案例:
public class Outter {
public void method() {
System.out.println("外部类的成员方法");
class Inner{
private String name;
public void method() {
System.out.println("局部内部类的方法");
}
}
Inner inner = new Inner();
inner.method();
}
public static void main(String[] args) {
Outter outer = new Outter();
outer.method();
}
}
局部内部类的使用范围就是局部范围,就是申明的范围内。 局部内部类无法使用任何访问修饰符修饰,也不能修饰为static
局部内部类访问外部类中的成员或者局部变量。
在局部内部类中可以访问外部了的任何成员。可以使用外部类的this对象等等。 在局部内部类中如果要使用外部类的局部变量,如果jdk是1.7之前,则局部变量必须是final修饰的,1.7之后就不需要了,其实就是默认就是final。
局部内部类在方法执行结束之后,内对象依然存在的情况:
public class A {
public void show() {
}
}
public class Outter {
public A getA() {
int x = 10;
class B extends A{
public void show() {
System.out.println(x);
}
}
B b = new B();
return b;
}
public static void main(String[] args) {
A a = new Outter().getA();
System.out.println(a);
a.show();
}
}
局部内部类的编译情况:
源代码:
public class Outter {
public void methoda() {
class Inner{}
}
public void methodb() {
class Inner{}
}
}
编译后的情况: 局部内部类编译后的类名是:外部类类名$index内部类类名.class 。 这里的index是编译器根据方法的编译前后顺序给的索引。
抽象内部类和内部接口
[1]内部类能不能申明为抽象类?
成员非静态内部类可以是抽象类,但是只能被内部类继承 [2]成员静态内部类可以被申明为抽象类.
public class Outter {
public abstract static class Inner{
}
class B extends Inner{
}
}
class A extends Outter.Inner{
}
[3]局部内部类,局部内部类可以申明为抽象的。
public class Outter {
public void method() {
abstract class Inner{
}
class A extends Inner{
}
}
}
[4]接口内部申明内部接口
接口中可以申明:内部接口,成员内部类,局部内部类。
public interface IOutter {
public interface IInner{
}
public class AInner {
}
public static class SAInner{
}
default void method() {
class Inner{
}
}
}
测试:
public class Test {
public static void main(String[] args) {
IOutter outter = new St();
IOutter.AInner ainner = new AInner();
IOutter.SAInner sainner = new SAInner();
IOutter.IInner iinner = new Geek();
}
}
class St implements IOutter{
}
class Geek implements IOutter.IInner{
}
接口中的静态方法:jdk8的新特性
匿名内部类
所谓匿名内部类就和匿名对象一样,没有名字。
常用来直接继承抽象类,或者实现接口。
匿名内部类只能使用一次,不能使用第二次。
案例:使用匿名内部类实现一个线程。
public class Main {
public static void main(String[] args) {
new Main().mt();
}
public void mt() {
new Thread() {
public void run() {
System.out.println("匿名内部类继承Thread类实现一个线程类");
method();
}
public void method() {
System.out.println("匿名内部类自定义的方法");
}
}.start();
new Thread(new Runnable() {
private String name = "runnable";
public void run() {
System.out.println("匿名内部类实现Runnable接口实现一个线程类");
System.out.println(name);
m();
}
}).start();
}
public void m() {
System.out.println("外部类的成员方法");
}
}
匿名内部类就是使用{}来实现或者继承某一个类。
常见的方式:
类名/接口 对象名 = new 类名/接口(){实现接口或者继承父类的重写的方法}
Thread ta = new Thread() {
public void run() {
System.out.println("一个线程");
}
};
ta.start();
使用场景:
当一个接口或者一个父类申明的抽象方法非常有限,而我们只需要这个类对象一次,这时就使用匿名内部类创建对象。
new Thread(new Runnable() {
private String name = "runnable";
public void run() {
System.out.println("匿名内部类实现Runnable接口实现一个线程类");
System.out.println(name);
m();
}
}).start();
匿名内部类中同样可以使用外部类的任何成员。
匿名内部类谈不上任何修饰符。
匿名内部类的编译:
匿名内部类也会被独立的编译成一个字节码文件,命名为 ”外部类类名$index.class”。 index就是编译器给所有的内部类给的索引。
静态内部类的单利中的使用
public class Singleton {
private static class Inner{
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return Inner.instance;
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
|