Java 内部类

转载自:http://kenby.iteye.com/blog/1603803

两种内部类

Java的内部类有两种,一种是静态内部类,另一种是普通内部类,普通内部类可以获得外部对象的引用,

所以在普通内部类能够访问外部对象的成员变量 ,也就能够使用外部类的资源,可以说普通内部类依赖

于外部类,普通内部类与外部类是共生共死的,创建普通内部类的对象之前,必须先创建外部类的对象。

创建普通内部类的代码如下:

Outer o = new Outer();

Outer.Inner inner = o.new Inner();

 

Outer.Inner inner = new o.Inner();         /* 错误 */

Outer.Inner inner = new Outer.Inner();  /* 错误 */

 

静态内部类没有外部对象的引用,所以它无法获得外部对象的资源,当然好处是,静态内部类无需依赖于

外部类,它可以独立于外部对象而存在。创建静态内部类的代码如下:

Outer.Inner inner = new Outer.Inner();

 

静态类的使用场景

在以下场合可以使用静态内部类:

(1) 外部类需要使用内部类,而内部类无需使用外部类的资源

(2) 内部类可以独立外部类创建对象

使用静态内部类的好处是加强了代码的封装性以及提高了代码的可读性,举个例子:

 

Java代码  收藏代码
  1. public class Person{    
  2.      //姓名    
  3.      private String name;    
  4.      //家庭    
  5.      private Home home;    
  6.      //构造函数设置属性值    
  7.      public Person(String _name){    
  8.           name = _name;    
  9.      }    
  10.      /* home、name的getter/setter方法省略 */    
  11.    
  12.      public static class Home{    
  13.           //家庭地址    
  14.           private String address;    
  15.           //家庭电话    
  16.           private String tel;    
  17.    
  18.           public Home(String _address,String _tel){    
  19.             address = _address;    
  20.             tel = _tel;    
  21.           }    
  22.           /* address、tel的getter/setter方法省略 */    
  23.      }    
  24. }   

 

把Home放在Person内部,一看便知道Home是Person的一个属性。使用的时候也很方便,如下代码:

 

Java代码  收藏代码
  1. public static void main(String[] args) {    
  2.     Home home = new Person.Home("上海""021");  
  3.     Person p1 = new Person("张三");    
  4.     Person p2 = new Person("李四");    
  5.     p1.setHome(home);    
  6.     p2.setHome(home);    
  7. }   

 

这里创建一个home对象,p1和p2都使用这个home对象,p1和p2共享同一个home对象。

如果把Home换成普通内部类,情况就不同了,这时代码变成:

 

Java代码  收藏代码
  1. public static void main(String[] args) {    
  2.     Person p1 = new Person("张三");    
  3.     Home home = p1.new Home("上海""021");  
  4.     p1.setHome(home);    
  5.     Person p2 = new Person("李四");    
  6.     p2.setHome(home);    
  7. }   

 

这里p1和p2依然共享同一个home对象,但此时home对象和p1是同生共死的,如果p1对象消亡,那么p2就没有

家了,这对p2来说实在不公平,而如果为p1和p2都创建一个Home对象,又浪费资源。所以在这个例子中,

使用静态内部类比普通内部类要合适。


Java Singleton 写法:public class Smarty {
    private Smarty() {}
    
    private static class SmartyLoader {
        private static final Smarty instance = new Smarty();
    }

    public static Smarty getInstance() {
        return SmartyLoader.instance;
    }
}

作者:吴强
链接:https://www.zhihu.com/question/29971746/answer/46320214
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

静态内部类和普通内部类的区别

(1)普通内部类不能声明static的方法和变量

普通内部类不能声明static的方法和变量,注意这里说的是变量,常量(也就是final static修饰的属性)

还是可以的,而静态内部类形似外部类,没有任何限制。

(2)使用静态内部类,多个外部类的对象可以共享同一个内部类的对象。

使用普通内部类,每个外部类的对象都有自己的内部类对象,外部对象之间不能共享内部类的对象


成员内部类里面为什么不能有静态成员和方法?

(转载https://www.cnblogs.com/YLQBL/p/6496511.html)

非静态内部类不能有静态成员!

成员内部类必须先实例化外部类对象然后再实例化成员内部类;

非static的内部类,在外部类加载的时候,并不会加载它,所以它里面不能有静态变量或者静态方法。
1、static类型的属性和方法,在类加载的时候就会存在于内存中。
2、要使用某个类的static属性或者方法,那么这个类必须要加载到jvm中。
基于以上两点,可以看出,如果一个非static的内部类如果具有static的属性或者方法,那么就会出现一种情况:内部类未加载,但是却试图在内存中创建static的属性和方法,这当然是错误的。原因:类还不存在,但却希望操作它的属性和方法。

java很多想这类不能共同存在的 一般都与他们的生命周期有关。。。
比如 静态成员和静态方法是随着类的加载而存在的,也就是说内部类的静态属性是随着类的加载的,但是内部类的实例 是创建后才存在的,也就是说其静态属性优先存在于他的类实例的存在 这显然是矛盾的,所以要把内部类设为静态的 这样他们的生命周期就是相同了;

如果内部类没有static的话,就需要实例化内部类才能调用,说明非static的内部类不是自动跟随主类加载的,而是被实例化的时候才会加载。
而static的语义,就是主类能直接通过内部类名来访问内部类中的static方法,而非static的内部类又是不会自动加载的,所以这时候内部类也要static,否则会前后冲突。


匿名内部类-回调-闭包

转载于:https://www.cnblogs.com/highriver/archive/2010/09/09/1822392.html)

详解内部类请参考:https://blog.csdn.net/chenssy/article/details/13170015

首先明确闭包的概念:一个代码段被用来做为方法的参数.
java中没有直接使用某个方法做为另一个方法的参数的,java使用匿名内部类来模拟这种情况。

匿名内部类往往是做为一个内部类(接口)的具体实现。在一些平台类(platform class)中有一些模板方法。模板方法的包含了固定流程。其中某些步骤是调用了内部类(接口)中的某些方法。但是平台类将这些方法的具体实现延迟到了业务类中。业务类调用平台类的模板方法,但是传入匿名内部类的实现做为模板方法的参数。

示例:

package callback;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class AnonymousBusinessTemplateExample2 {

// 内部接口也是回调接口,只定义抽象方法。
private interface Callback {
Object doIt(Connection conn)
throws SQLException;
}

// 模板方法(抽象)
private Object execute(Callback callback) throws SQLException {
Connection conn
= openConnection();
try {
return callback.doIt(conn);
}
finally {
closeConnection(conn);
}
}

// 业务方法(具体)
public Object sqlQuery(final String sql) throws SQLException {
//匿名内部类做为模板方法的参数来模拟闭包
return execute(new Callback() {
public Object doIt(Connection conn) throws SQLException {
return conn.createStatement().executeQuery(sql);
}
});
}

public Connection openConnection() throws SQLException {
return DriverManager.getConnection("", null);
}

public void closeConnection(Connection conn) throws SQLException {
if (conn != null && !conn.isClosed()) {
conn.close();
}
}
}

一般内部接口比内部类用的更多。内部类中的方法可以有默认的实现。匿名内部类做为业务方法的参数传入时,会override默认的方法。内部接口的话,没有默认的实现。完全将具体的实现交给了匿名内部类。

匿名内部类的思想是回调,即好茉坞原则。回调的一个好处是decouple。 客户端只需要关心业务(比如匿名内部类的具体实现)而不用再关心一些资源的连接释放什么的,这些交给平台类中的模板方法。ruby的闭包还支持对数组中的每个元素,文件中的每行,结果集中的每个记录的操作。而用java实现这样的迭代并操作其中元素非常麻烦。感觉java中用的多的偏模板方法,即逻辑中固定一些流程,初始化及释放某些资源。


为什么需要内部类?

java内部类有什么好处?为什么需要内部类?

首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以创建一个内部类实现这个接口。由于内部类对于外部类的所有内容都是可以访问的,所以这样做可以完成你直接实现这个接口的功能。

不过你可能要质疑,更改一下方法不就可以了吗?

的确,以此作为设计内部类的理由,没有说服力。

真正的原因是这样的,java中的内部类和接口或抽象类加在一起,可以解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,c++的多继承设计起来很复杂,而java通过内部类+接口,可以很好的实现多继承的效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章