一文搞定java的四种内部类
一:成员内部类
1.成员变量 与成员内部类
成员变量:在类中定义的,没有staitc修饰符的变量称为成员变量,也称为实例变量
成员变量的特点:
1.每个实例都有这样的变量
2.要在main方法中调用成员变量(实例变量),必须先要创建对象,然后才能调用实例变量
在类中定义的没有static修饰符的内部类称为成员内部类
实际上,jvm就是把成员内部类当做是类中的一个成员方法,可以直接访问外部类中私有的成员变量和私有的成员方法
成员内部类的特点和成员变量的特点类似:要创建成员内部类的对象,必须先要创建外部类的对象.然后通过外部类的对象来创建内部类的对象
public class Outer {
private int index;
private void test() {
System.out.println("Outer类私有的test方法被调用,访问Outer类中私有的属性 index=" + index);
}
public Outer(int index) {
this.index = index;
}
protected class Inner {
private int index;
// 注意:在成员内部了中不能有静态属性
//private static int index2;
public void fun() {
System.out.println("Inner类的实例方法fun()被调用,访问Inner类中的私有的实例属性 index="
+ index);
// Outer.this就是在内部类中持有的一个外部类对象的引用
// Outer.this.index 就是标识的外部类中的私有的成员变量
System.out
.println("在Inner类中访问外部类私有的成员变量 index=" + Outer.this.index);
test();
}
public Inner(int index) {
this.index = index;
}
}
}
外部调用
public class Main {
public static void main(String[] args) {
// 要创建成员内部类的对象,必须先要创建外部类的对象.
Outer outer = new Outer(100);
// 然后通过外部类的对象来创建内部类的对象
Outer.Inner inner = outer.new Inner(500);
inner.fun();
}
}
补充:当一个具体类继承了一个抽象类A并且实现了一个接口B,如果A,和B的抽象方法相同,那么具体类中就会出现只实现一个该方法的情况,遇到这种情况我们可以让该类继承A在该类的内部创建成员内部类实现B那么该成员内部类就相当与接口中方法的实现。
二:静态内部类
静态变量与静态内部类
在类中声明的有static修饰符的变量称为静态变量
静态变量的特点:
1.静态变量在内存中只有一份,被这个类所有的对象所共享
2.调用静态变量的时候不需要创建对象,可以直接通过类名来调用
静态内部类的特点:
在类中定义的有static修饰符的内部类称为静态内部类.在静态内部类中可以定义静态属性
实际上,jvm就是把静态内部类当做是类中的一个静态方法,可以直接访问外部类中私有的静态变量和私有的静态方法
静态内部类的特点和静态变量的特点类似:创建静态内部类的对象的时候,不需要创建外部类的对象
public class Outer {
private int index1;
private void test1() {
System.out .println("Outer类私有的test方法被调用,访问Outer类中私有的属性 index1=" + index1);
}
private static int index = 100;
private static void test() {
System.out.println("Outer类中私有的静态方法被调用,访问Outer类中私有的静态属性 index=" + index);
}
public Outer(int index) {
}
protected static class Inner {
private static int index;
public void fun() {
System.out.println("Inner类的实例方法fun()被调用,访问Inner类中的私有的静态属性 index="
+ index);
// 在静态内部类中不能访问外部类中私有的成员变量和私有的成员方法
// System.out
// .println("在Inner类中访问外部类私有的成员变量 index1=" + index1);
// test1();
// 可以在静态内部类中直接访问外部类私有的静态属性和私有的静态方法
System.out.println("在静态内部类中访问外部类中私有的静态属性 inxex=" + Outer.index);
test();
}
public Inner(int index) {
this.index = index;
}
}
}
外部调用
public class Main {
public static void main(String[] args) {
// 创建静态内部类的对象的时候,不需要创建外部类的对象
Outer.Inner inner = new Outer.Inner(500);
inner.fun();
}
}
**三:局部内部类(此类为难点)
java是前向的编程语言.所以前向是指在使用这种类型之前必须先要把这种类型声明好,声明找之后才能使用
我们在方法的第返回类型中使用Inner的时候,Inner这种类型还没有声明,所以方法的返回类型写成Inner是不行的
但是Inner类是继承自Object类的,所以方法的返回类型可以写成Object
局部变量与局部内部类
在方法中或代码块中{}声明的变量称为局部变量
局部变量的特点:
1.局部变量只在它声明的{}里面有效
2.局部变量不能使用访问权限修饰符
局部内部类的特点
在方法或代码块中声明的内部类,称为局部内部类
局部内部类的特点和局部变量的特点一致
1.局部内部类是一种类型,而这种类型只在它声明的{}里面有效
2.局部内部类不能使用访问权限修饰符
public class Outer {
public static IA test() {
String addr = "北京";
class Inner implements IA {
private int index;
@Override
public void fun() {
System.out.println("局部内部类的实例方法被调用,访问类中实例属性 index=" + index);
}
public Inner(int index) {
this.index = index;
}
}
Inner inner = new Inner(100);
return inner;
}
}
内部类实现的接口
public interface IA {
//接口中必须有你要从外界调用的方法;
void fun();
}
外部调用
当我们调用Outer.test()的时候,该方法返回了一个Inner类的对象.但是这个Inner类的对象
被当做Object类型的.我们需要调用Inner类方法,就需要把obj还原成Inner类型的
但是Inner这种类型仅仅在Outer类的test()方法中有效,除了这个方法就无法识别Inner类型
由于无法识别Inner类型,也就无法对obj进行类型转换,无法类型转换,也就无法调用Inner类中的特有方法
所以:Outer类的test()方法的返回类型写Object也是不行的
// Object obj = Outer.test();
// (Outer.Inner)obj;
public class Main {
public static void main(String[] args) {
//正确的调用方法,另该内部类实现某接口(接口中必须有你要调用的方法),通过接口类型调用方法:
//能调用到局部内部类中的方法,自然也就能通过方法访问外部类对象了
IA ia = Outer.test();
ia.fun();
}
}
**四:匿名内部类(最常用)
package com.powernode.innerclass.test7;
如果一个局部内部类只会使用一次,用完之后就再也不会使用了,就可以把这个局部内部类改造成一个匿名内部类
匿名内部类一定是实现一个接口或继承一个抽象类的,匿名内部类就是一个特殊的局部内部类.
注意:以上说法是错误的,准确的概念应该是,匿名内部类一定是实现了一个接口或继承了一个类,
示例代码:
public class test02 {
public static void main(String[] args) {
//匿名内部类方式一
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
});
t1.start();
//匿名内部类方式二 ,这种方式很少见相当于大括号就是实现.
Thread t2 = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t2.start();
}
}
匿名内部类有两种使用形式
1.出现在方法的返回值当中
2.出现在方法调用的实参中
// 下面的代码是匿名内部类的第一种使用形式:匿名内部类出现在方法的返回值当中
public class EngineFactory {
public IEngine getEngine(String eName) {
if ("红旗".equals(eName)) {
// 当我们判断到eName是"红旗"的时候,我们应该执行的操作是
// 1.声明一个具体类,实现IEngine这个接口并且实现其中的全部的抽象方法
// 2.创建这个具体类的对象,当做方法的返回(这不过这个对象没有名字)
return new IEngine() {
@Override
public void start() {
System.out.println("红旗发动机启动,速度40");
}
@Override
public void speedup() {
System.out.println("红旗发动机加速,速度60");
}
@Override
public void stop() {
System.out.println("红旗发动机停止,速度0");
}
};
} else if ("奇瑞".equals(eName)) {
return new IEngine() {
@Override
public void start() {
System.out.println("奇瑞发动机启动,速度30");
}
@Override
public void speedup() {
System.out.println("奇瑞发动机加速,速度50");
}
@Override
public void stop() {
System.out.println("奇瑞发动机停止,速度0");
}
};
} else {
System.out.println("发动机型号错误,不能创建发动机对象");
return null;
}
}
}
内部类实现的接口
public interface IEngine {
public abstract void start();
public abstract void speedup();
public abstract void stop();
}
测试类
public class Car {
public void testEngine(IEngine e) {
e.start();
e.speedup();
e.stop();
}
}
外部调用
public class Main {
public static void main(String[] args) {
Car car = new Car();
EngineFactory ef = new EngineFactory();
//直接使用接口类型来接受返回的对象,使用
IEngine e1 = ef.getEngine("红旗");
if (e1 != null) {
car.testEngine(e1);
}
}
}
匿名内部类的第二种使用形式:匿名内部类出现在方法的返回值当中
这种方式在Android的设置监听器中很常见,这里就不在赘述了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.