基本介绍
一个类的内部又完整的嵌套了另外一个类的结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类,是类的第五大成员(属性,方法,构造器,代码块,内部类)。内部类最大的特点就是可以直接访问私有属性。
分类:
定义在外部类的局部位置上(比如方法内):局部内部类(有类名),匿名内部类(没有类名)
定义在外部类的成员位置上:成员内部类(没有用static修饰),静态内部类(使用static修饰)
局部内部类:
定义在外部类的局部位置,比如方法中,并且有类名
- 可以直接访问外部类的所有成员,包含私有
- 不能添加访问修饰符,因为他的地位就是一个局部变量,局部变量不能使用修饰符。但是可以用final修饰。
- 作用域仅仅在定义它的方法或者代码块中
- 局部内部类访问外部类的成员,直接访问
- 外部类访问局部内部类的成员,先创建对象,在进行访问
- 外部其他类(与内部类无关联的类)不能访问局部内部类
- 如果外部类和局部内部类的成员重名。默认遵循就近原则,如果想要访问外部类的成员,则可以使用外部类.this.成员去访问
1--5点举例
package Learn;
class Outer {
private int outerNum=1;
public void outerFunction(){
System.out.println("外部类Test的方法");
class Inner{
private int innerNum=10;
public void innerFunction(){
System.out.println("内部类TestInner的方法");
//可以直接调用
System.out.println("外部类的私有的数值为"+outerNum);
}
}
//在方法区中创建对象,使用内部类以及他的相关成员
Inner inner=new Inner();
inner.innerFunction();
System.out.println(inner.innerNum);
}
}
public class Test {
public static void main(String[] args) {
Outer outer=new Outer();
outer.outerFunction();
}
}
第7点举例
public class Test {
int a=0;
public void sum(){
class Inner{
int a=6;
public void sum1(){
System.out.println(a+Test.this.a);
}
}
}
}
匿名内部类
匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名(一定意义上说该类是拥有名字,但是不是我们所定义的,是由系统定义的,但是我们不可以直接知道他的名字),但是注意他的本质还是一个类,同时还是一个对象。匿名内部类使用是在该类仅仅使用一次,以后不会再次使用,此时重新创建一个类成本比较高,使用匿名内部类。
匿名内部类的基本语法:
new 类或者接口(参数列表){
类体};
下面是我们实现接口方法时常用的方法
package Learn;
public class Test {
public static void main(String[] args) {
Tiger tiger=new Tiger();
tiger.cry();
}
}
interface Animal{
public void cry();
}
class Tiger implements Animal{
@Override
public void cry() {
System.out.println("我是老虎");
}
}
但是如果我们仅仅使用一次tiger这个类,重新创建一个类太麻烦,这个时候我们使用匿名内部类
package Learn;
public class Test {
public static void main(String[] args) {
Animal tiger=new Animal() {
@Override
public void cry() {
System.out.println("我是老虎");
}
};
tiger.cry();
/*我们根据下面的输出语句可以了解到,Animal tiger=new Animal() ,其编译类型为Animal,而其运行类型在jdk底层实际为
* class Test$1 implements Animal(){
* @Override
* public void cry() {
System.out.println("我是老虎");
}
* }
*/
System.out.println("tiger对象对应的类名为"+tiger.getClass());
}
}
interface Animal{
public void cry();
Animal tiger=new Animal() {
@Override
public void cry() {
System.out.println("我是老虎");
}
};
}
所以我们可以总结出匿名内部类的以下特点:
匿名内部类可以简化开发,但是该类只能使用一次,即上述例子中的Test$1只能使用一次,我们使用过后该类就直接消失了。即我们不能在创建一个Animal lion =new Test$1,但是我们创建的tiger却可以一直使用。
那么我们基于类进行匿名内部类的使用(注意与我们创建普通类对象的区别)
package Learn;
public class Test {
public static void main(String[] args) {
Animal tiger1=new Animal("猫猫");
Animal tiger2=new Animal("花花") {
};
/*我们根据下面的输出语句可以了解到,Animal tiger2=new Animal() ,其编译类型为Animal,而其运行类型在jdk底层实际为
* class Test$1 extend Animal(){
*
* }
*/
System.out.println("tiger1对象对应的类名为"+tiger1.getClass());
System.out.println("tiger2对象对应的类名为"+tiger2.getClass());
}
}
class Animal{
String name;
public Animal(String name){
}
}
当我们到这里,其实也可以发现我们的匿名内部类的名称其实在外部类+$1。
匿名内部类的使用细节:
- 匿名内部类既是一个类,也是一个对象,因此可以使用两种方法进行调用,上述刚刚使用类进行调用,看下我们利用对象进行调用。可以发现我们连tiger都忽略了,直接使用了cry方法。
package Learn;
public class Test {
public static void main(String[] args) {
new Animal() {
@Override
public void cry() {
System.out.println("我是老虎");
}
}.cry();
}
}
interface Animal{
public void cry();
Animal tiger=new Animal() {
@Override
public void cry() {
System.out.println("我是老虎");
}
};
}
- 匿名内部类不能添加访问修饰符,因为其本身就是一个局部变量。所以外部其他类不能直接访问匿名内部类
经典使用案例:我们不需要直接去写一个新的类来实现这个方法。
package Learn;
public class Test {
public static void main(String[] args) {
Test.f1(new AA() {
@Override
public void show() {
System.out.println("输出");
}
});
}
public static void f1(AA aa){
aa.show();
}
}
interface AA{
void show();
}
成员内部类
定义在外部类的成员位置上,可以访问外部类的所有成员,包括私有的,同时也可以添加修饰符。
package Learn;
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.say();
}
}
class Outer{
private int a=0;
class Inner{
void show(){
System.out.println(a);
}
}
public void say(){
Inner inner = new Inner();
inner.show();
}
}
外部其他类如何访问成员内部类
方法1,利用outer的对象实例进行调用
package Learn;
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
System.out.println(inner.b);
}
}
class Outer{
private int a=0;
class Inner{
int b=1;
void show(){
System.out.println(a);
}
}
}
方法2,利用方法进行调用
package Learn;
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.getInner().b);
}
}
class Outer{
private int a=0;
class Inner{
int b=1;
void show(){
System.out.println(a);
}
}
public Inner getInner(){
return new Inner();
}
}
静态内部类
定义在成员位置,有static修饰,可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员,可以添加任意的修饰符。而外部类访问静态内部类,需要创建实例对象才可以访问。
package Learn;
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
//外部其他类访问静态内部类
System.out.println(outer.getInner().b);
}
}
class Outer{
static int a=0;
static class Inner{
int b=1;
}
public Inner getInner(){
return new Inner();
}
public int getB(){
//外部类访问静态内部类
Inner inner=new Inner();
return inner.b;
}
}