内部类:顾名思义,就是在一个类的内部创建一个新类,也就是俗话说的把类的定义置于外围类的里面。
e.g:
public class Test {class Contents{
private int i = 11;
public int value(){
return i;
}
}
class Destination {
private String label;
Destination(String whereTo){
label = whereTo;
}
String readLabel(){
return label;
}
}
public void ship(String dest){
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args){
Test t = new Test();
t.ship("Tasmania");
}
}
//console
Tasmania
从上看他们的区别也就只是内部类嵌套在Test里面;
2.连接到外部类:
内部类除了只是一种名字隐藏和组织代码的模式,还有其他的用途,当生产一个内部类时,此对象与制造他的外围对象之间天然就有了一种联系,所有她能访问其外围对象的所有成员,且不需要任何特殊条件,也就是内部类还拥有其外围类的所有元素的访问权限。
e.g:
public class Sequence {
private Object[] items;
private int next = 0;
/**
*
* <b>构造方法</b>
* <br/>
* @param size
*/
public Sequence(int size) {
items = new Object[size];
}
/**
*
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param x
*/
public void add(Object x){
if(next < items.length){
items[next++] = x;
}
}
private class SequenceSelector implements Selector{
private int i = 0;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if(i<items.length){
i++;
}
}
}
public Selector selector(){
return new SequenceSelector();
}
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
Sequence sequence = new Sequence(10);
for(int i = 0;i<10;i++)
sequence.add(Integer.toString(i));
Selector selector = sequence.selector();
while(!selector.end()){
System.out.print(selector.current()+",");
selector.next();
}
}
}
interface Selector{
boolean end();
Object current();
void next();
}
3.使用.this与.new
若需要生成对外部类的引用,可以使用外部类的名字后面紧跟圆点和this,这样产生的引用自动地具有正确的类型,这一点在编译器就被知晓并受到检查,因此没有任何运行时开销。
public class DoThis {
void f(){
System.out.println("Dothis.f()");
}
void b(){
System.out.println("Dothis.d()");
}
public class Inner{
public DoThis outer(){
//
return DoThis.this;
}
}
public Inner inner(){
return new Inner();
}
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
DoThis dt = new DoThis();
DoThis.Inner dti = dt.inner();
dti.outer().f();
dti.outer().b();
}
}
.new 的作用是在需要让其他某一个对象去创建其某一个内部类的对象,要创建其某个内部类的对象,要实现这个目的,那么则需要在new表达式中提供对其外部类对象的引用
public class DotNew{
public class Inner{}
public static void main(String[] args){
DotNew dn = new DotNew();
// .new的使用
DotNew.Inner dni = dn.new Inner();
}
}
在拥有外部类对象之前是不可能创建内部类对象的,这是由于内部类对象会暗暗的连接到其创建它的外部类对象上,但若果你创建的是嵌套类(静态内部类),那么则不需要外部类的对象的引用
4.内部类与向上转型:
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类的作用就显现出来了(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的)。这是因为此内部类是某一个接口的实现,能够完全不可见,且不可用。而所得到的只是指向基类或接口的引用,所以能够很方便的隐藏实现细节。
public class TestParcel {
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Contents c = p.contents();
Destination d = p.description("Tasmania");
}
}
interface Destination{
// 接口方法默认的都是public
String readLabel();
}
interface Contents{
// 接口方法默认的都是public
int value();
}
class Parcel4{
private class PContents implements Contents{
private int i = 12;
@Override
public int value() {
return i;
}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label = whereTo;
}
@Override
public String readLabel() {
return label;
}
}
public PDestination description(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
}
从这个例子可以看出,内部类PContents 是私有的,private访问权限的,除了Parcel4,其他都不可以访问,内部类PDestination 是包访问权限,也就是只有Parcel4及其子类,还有和Parcel4同一个包中的类能够访问,其他类都不能访问该内部类。甚至可以说是向下转型成private内部类都不可以(或protected内部类,除非是继承自它的子类),因为不能访问其名字,就像在TestParcel类中看到的那样,于是,private内部类给类提供了一种途径,通过这种方式可以完全阻止任何依赖与类型的编码,完全隐藏来实现的细节。
5. 在方法和作用域内的内部类
顾名思义,就是可以在一个方法里面或在任意的作用域定义内部类,这样做的理由如下:
1.实现了某类型的接口,可以创建并返回对其的引用;
2.当解决一些复杂的问题的时候,创建了一个辅助类来完成,但是又不希望这个类时公共可用的
1).展示在方法的作用域内创建一个完整的类-----------------------------------局部内部类
public class Parcel5 {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label = whereTo;
}
@Override
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
Parcel5 p = new Parcel5();
Destination d = p.destination("Tasmanis");
}
}
PDestination是destination()方法的一部分,而不是Parcel的一部分,所以在destination()之外不能访问PDestination,在return中返回的其基类的引用,也就是向上转型.
6.嵌套类(静态内部类)
一般不需要内部类对象与其外围类对象之间有联系,那么可以将内部类申明为static。
嵌套类意味着:
1)要创建嵌套类的对象,并不需要其外围类的对象;
2)不能从嵌套类的对象中访问非静态的外围类对象。
普通内部类和嵌套类的区别:普通内部类的字段和方法,只能放在类的外部层次上,所以普通内部类不能有static数据和static字段,也不能包含嵌套类。但反之嵌套类则可以包含这些所有的东西
7.接口内部的类
一般情况下,不能再接口内部放置任何代码,但嵌套类却可以作为接口的一部分。放到接口中的任何类都会自动变成public和static,由于类时static的,只是将嵌套类置于接口的命名空间内,并不违反接口的规则,甚至可以在内部类中实现其外围接口,如下、:
public interface ClassInInterface{
void howdy();
class Test implements ClassInInterface{
public void howdy(){
System.out.println("Howdy!");
}
public static void main(String[] args){
new Test().howdy();
}
}
}
内部类的作用 : 每个内部类都能独立的继承自一个接口的实现,无论外围类是否已经继承了某个接口的实现,对于内部类都没有影响,甚至可以说这是一种多继承的解决办法
内部类的其他特性:1).内部类可以有多个实例,每个实例都有自己的状态信息,且和外围类的实例互相独立;
2).在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类;
3).创建内部类对象的时刻并不依赖与外围类对象的创建;
4).内部类并没有令人迷惑的"is - a" 关系,就是一个独立的实体。
8.闭包和回调:
闭包:一个可调用的对象,记录了一些信息,这些信息来自语创建它的作用域,从定义可以看出内部类时面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有了指向此外围类对象的引用。在这个作用域中,内部类有权操作所有的成员,包括private成员。
有些人认为java应该包含某种类似指针的机制,以此来允许回调(callback),通过回调,对象能够携带一些信息,在这些信息允许它在稍后的某个时刻调用初始的对象,通过内部类提供闭包的功能时解决这个问题的好方案,比指针更安全。
e.g:
public class CallBack {
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallBackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
// create a interface
interface Incrementable{
void increment();
}
// a simple class to implement the interface
class Callee1 implements Incrementable{
private int i = 0 ;
@Override
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement{
public void increment(){
System.out.println("other operation");
}
static void f(MyIncrement mi){
mi.increment();
}
}
// 由于这个类有一个increment(),想要在其他方法里面实现,那么只有使用内部类
class Callee2 extends MyIncrement{
private int i = 0;
public void increment(){
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable{
@Override
public void increment() {
// 指定调用外部方法,防止死循环
Callee2.this.increment();
}
}
Incrementable getCallBackReference(){
return new Closure();
}
}
class Caller{
private Incrementable callbackReference;
Caller(Incrementable cbh){
callbackReference = cbh;
}
void go(){
callbackReference.increment();
}
}
9.内部类的继承:由于内部类构造器必须连接指向其外围类的引用。所以在继承内部类的时候,指向外围类对象的引用必须初始化,在派生类中不在存在可连接的默认对象;
public class InnerClassExtends extends WithInner.Inners{
InnerClassExtends(WithInner w){
w.super();
}
/**
* <b>方法说明:</b>
* <ul>
*
* </ul>
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
InnerClassExtends m = new InnerClassExtends(new WithInner());
m.test();
m.test();
}
}
class WithInner{
public void tt(){
}
class Inners{
public void test(){}
}
}