学习笔记(五)接口与内部类(二)

来源:互联网 发布:企业怎样做网络推广 编辑:程序博客网 时间:2024/06/05 11:21

《Java编程思想》整理的一些学习笔记,有不对的地方,欢迎指出。

1.在匿名类中定义字段时,对其进行初始化操作。

interface Mount1{
String readLabel();
}
public class Fight1 {
public Mount1 mount(final String s){
return new Mount1(){
private String label = s;
public String readLabel(){
return label;
}
};
}
public static void main(String[] args){
Fight1 f = new Fight1();
Show.say(f.mount("Hello World").readLabel());
}

}

2.通过实例初始化,为匿名内部类创建一个构造器效果。
abstract class Base{
public Base(int i){
Show.say("Base constructor, i = "+i);
}
public abstract void f();
}
public class AnonymousConstructor {
public Base getBase(int i){
return new Base(i){
{Show.say("Inside instance initializer");}
public void f(){
Show.say("In anonymous f()");
}
public void g(){
Show.say("In anonymous g()");
}
};
}
public static void main(String[] args){
AnonymousConstructor a = new AnonymousConstructor();
Base base = a.getBase(123);
base.f();
   //! base.g();   不可以,此时base指向子类对象,子类中特有的方法不可以调用,只能调用重写于父类的方法。
}
}

如果要在getBase()方法内部使用 i ,则 getBase()中的参数i 必须被设为 final 。

3.当在方法内部使用参数时的情况,将参数设置为final。

import vip.Show;


public class Fight2 {
public Destination dest(final float price,final String dest){
return new Destination(){
private int cost;
private String label = dest;
{
cost = Math.round(price);
if(cost>100)
Show.say("Over budget!");
}
public String readLabel(){ return label; }
};
}
public static void main(String[] args){
Fight2 f = new Fight2();
Destination d = f.dest(123.23F, "Tanzania");
}
}

输出结果:

Over budget!

4.内部类的其他用途,当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一定的联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有访问权。

interface Selector{
public boolean end();
public Object current();
public void next();
}
public class Sequence {
private Object[] object;
private int next = 0;
public Sequence(int size){ object = new Object[size]; }
public void add(Object x){
if(next < object.length)
object[next++] = x;
}
private class SSelector implements Selector{
private int i =0;
public boolean end(){ return i == object.length; }
public Object current(){ return object[i]; }
public void next(){ if(i < object.length) i++; }
}
public Selector getSelector(){
return new SSelector();
}
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.getSelector();
while(!selector.end()){
System.out.println(selector.current());
selector.next();
}

}
}

所以内部类自动拥有对其外围类的所有成员访问权。当某个外围类的对象创建了一个内部类对象时,次内部类对象必定会保存一个指向那个外围类对象的引用。然后,在你访问此外围类的成员时,就是用那个“隐藏的”引用来选择外围类的成员。幸运的是,编辑器会帮你处理所有的细节,但是,内部类的对象只能在与其外围类的对象相关联的情况下才被创建。构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器找不到这个引用就会报错。

5.如果不需要内部类对象与其外围类对象之间有联系,可以将内部类声明为static。这通常称为嵌套类。想要理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式的保存了一个引用,指向创建它的外围类对象。而嵌套类意味着:1.要创建嵌套类的对象,并不需要其外围类的对象。2.不能从嵌套类的对象中访问非静态的外围类对象。此外,普通内部类的字段和方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类(原因:非静态内部类依赖于外部类对象 ,

 java虚拟机要求所有的静态变量必须在对象创建之前完成,所以如果内部类要有static的话,必须在创建对象之前完成静态变量的加载,,这是互相矛盾的。换句话说静态字段不依赖对象,是于类相关的,在加载内容类的静态内容时,还没有外部类对象,所有编译就出现问题了)。但是嵌套类可以包含所有这些东西。
6.正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分,因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。
public interface IInetrface {
static class Inner{
int i,j,k;
public Inner(){}
void f(){}
}
}
7.有时候想要某些对象生成其自身内的某个内部类的对象。要想如此,必须在new表达式中提供一个引用,指向那个外围类的对象。但是不能想当然的认为只需加上外围类的名字就可以按照通常的样子生成内部类对象,而是必须,必须使用此外围类的对象来创建其内部类的对象:Fight4.Mount2 mount2 = f.new Mount2();而不是:Fight4.Mount2 mount2 = Fight4.new Mount2();  多层嵌套原理和它差不多,创建对象方法一样。
public class Fight4 {
class Mount2{
private int i = 123;
public int value(){return i;}
}
class Mount3{
private String label;
Mount3(String mount){ label = mount; }
String readLabel(){ return label; }
}
public static void main(String[] args){
Fight4 f = new Fight4();
Fight4.Mount2 mount2 = f.new Mount2();
System.out.println(mount2.value());
}
}
8.内部类的继承。因为内部类的构造器必须连接到指向其外围类对象的引用(构造内部类必须给它一个外部类对象的引用,内部类依赖于外部类对象),所以在继承内部类的时候,需要在导出类的构造器中手动加入对基类构造器的调用。在下例子中,需要给导出类InheritInner一个来自内部类的外围类中的引用。普通的继承,只需在导出类构造器中加入super();(当为缺省是,jvm自动添加),而内部类则需要  外围类对象引用.super();
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
9.当继承外围类,并在导出类中重写内部类时,这会不会像方法重写一样,运行导出类的方法? 答案是不会,这两个内部类是完全独立的两个实体,各自在自己的命名空间内。
10.局部内部类和匿名内部类的比较。它们具有相同的行为和能力。但是使用局部内部类而不使用匿名内部类的唯一理由是:需要不止一个该内部类的对象。
import vip.Show;


interface Counter{
int next();
}
public class Fight5 {
private int count = 0;
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){
Show.say("Localcounter()");
}
public int next(){
Show.say(name);
return count++;
}
}
return new LocalCounter();
}
Counter getCounter2(final String name){
return new Counter(){
{
Show.say("Counter()");
}
public int next(){
Show.say(name);
return count++;
}
};
}
public static void main(String[] args){
Fight5 f = new Fight5();
Counter c1 = f.getCounter("Local inner");
Counter c2 = f.getCounter2("Anonymous inner");
for(int i = 0; i < 5; i++)
System.out.println(c1.next());
for(int i = 0; i < 5; i++)
System.out.println(c2.next());
}
}
11.每个内部类都能独一地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类提供了某种进入其外围类的窗口。内部类可以有效的解决“多重继承”问题。假设有一种情形:必须在一个类中以某种方式实现两个接口,这是我们有两种方法:1.直接implements两个接口。2.implement一个接口,另一个接口在内部类里实现。再假设有一种情形:如果想实现两个具体类或抽象类,则只有采用内部类的方法。即: class C extends A{ B makeB() { return new B() {} ;} } 。使用内部类可以获得其他一些特性:1. 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。 2. 在单个外围类中,可以让多个内部类以不用的方式实现一个接口,或继承同一个类。 3. 创建内部类对象的时刻并不依赖于外围类对象的创建。 4. 内部类并没有令人迷惑的“is a ”关系,它就是一个独立的实体。
12.

0 0
原创粉丝点击