Thinking in Java捞干货,写笔记
一、成员内部类
1.最基本使用
public class Demo {
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) {
Demo d=new Demo();
d.ship("Tasmania");
}
}
2.内部类可以访问外部类的成员
内部类可以访问外部类的成员变量。如下:
public class Demo {
private Object[] items;
private int next = 0;
public Demo(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
private class SequenceSelector implements Selector {
private int i = 0;
public boolean end() {
return i == items.length;
}
public Object current() {
return items[i];
}
public void next() {
if (i < items.length) {
i++;
}
}
}
public Selector selector() {
return new SequenceSelector();
}
public static void main(String[] args) {
Demo d = new Demo(10);
for (int i = 0; i < 10; i++) {
d.add(Integer.toString(i));
}
Selector selector = d.selector();
while (!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
}
}
interface Selector {
boolean end();
Object current();
void next();
}
因为在创建内部类对象的时候,内部类对象会捕获一个指向外部类对象的引用。访问外部类成员的时候,就是用这个引用来获取外部类成员的。内部类中也可以取得这个外部类对象引用。举例如下:
public class DotThis{
void f(){
System.out.println("DotThis.f()");
}
class Inner{
public DotThis outer(){
return DotThis.this;
//A plain "this" would be Inner's this
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
DotThis dt=new DotThis();
DotThis.Inner dti=dt.inner();
dti.outer().f();
}
}
当要在其他类中创建一个内部类对象的时候,可以使用.new语法。
public class DotNew{
public class Inner{
}
public static void main(String[] args){
Inner dni=new DotNew().new Inner();
}
}
当创造内部类对象的时候,如果这个内部类不是嵌套类(静态内部类),那么就必须要通过外部类对象,才能创建这个内部类对象,为什么呢,之前说过,因为这个内部类对象要获取外部类的引用啊。
并且在存在多个内部类的时候,多个内部类之间可以互相创建对象。例子就不举了。
小结:现在所说的都是成员内部类,其实内部类没那么复杂,既然叫做成员内部类了,他就只是类的成员罢了。他也可以带修饰符,他的修饰符和其他普通的成员变量的修饰符的意义也没有什么不同。
3.内部类权限修饰符
当内部类被private修饰的时候,该类只能被外部类内的方法使用,其他类不能获取该内部类的引用,因为是private的,所以其他类根本不知道存在一个这样的类。当然也可以作为一个成员变量使用,但是如果作为成员变量,则其他类并不能直接创建内部类的引用,需要用其他手段获取该引用,如下:
class Outer{
Inner in;
private class Inner implements a_interface{
void show(){
System.out.println("123");
}
}
}
interface a_interface{
void show();
}
class test{
//Inner in=new Outer().in;这是错误的,因为test并不知道Outer类有一个Inner内部类,因为是私有的
a_interface in=new Outer().in;//可以运用向上转型的方法获取private修饰的内部类。
}
小结:其实这也很好记,无论是public还是private,修饰到内部类上的时候,和他们修饰普通的成员变量(如string,int之类)的时候没什么不同,规则都一样,public就都能使用,private就类内可以用。所以规则就记住三条就好:1.先考虑外部类的权限,是否可以获取一个外部类对象。2.创建成员内部类对象的时候需要外部类对象。3.考虑内部类的权限,是否可以获取这样的一个内部类对象(或者说,在外部知不知道有这样一个内部类)。
二、方法和作用域内的内部类
当我们需要解决一个复杂的问题,想创建一个类来辅助解决问题,但是不希望这个类是公共可用的,甚至不希望在外部类之内的其他地方可以访问到这个辅助类。我们可以运用方法内的内部类
public class Outer {
public InterfaceDemo get_InterfaceDemo(String s) {
class InterfaceDemoTool implements InterfaceDemo {
private String label;
private InterfaceDemoTool(String label) {
this.label = label;
}
public String readLabel() {
return label;
}
}
return new InterfaceDemoTool(s);
}
public static void main(String[] args) {
Outer o = new Outer();
InterfaceDemo i = o.get_InterfaceDemo("123");
}
}
interface InterfaceDemo {
String readLabel();
}
当然在方法中还可以定义多个内部类,并且这些内部类之间的关系和普通一个Java文件中多个类之间的关系好像没什么不同。也可以相互继承和创建对象。另外在方法中的内部类不能加private等权限修饰符,只能加abstract和final修饰符。
另外也可以在某个作用域内创建内部类对象
if(a==b){
class inner{
}
new inner();
}
三、匿名内部类
下面这块代码中get_inner()的意思是,创建一个继承自InnerFather的匿名类对象,并且自动向上转型为InnerFather后返回。
public class Outer {
public InnerFather get_inner() {
return new InnerFather() {
void print(){
System.out.println("Inner_Override");
}
};
}
class InnerFather {
InnerFather() {
}
void print(){
System.out.println("InnerFather");
}
}
public static void main(String[] args) {
Outer o = new Outer();
InnerFather i = o.get_inner();
i.print();
}
}
当然这只是有无参构造函数,当父类只有一个含参构造函数的时候,我们可以这样向匿名内部类传入一个构造函数参数。
public class Outer {
public InnerFather get_inner(int i) {
return new InnerFather(i) {
void print(){
System.out.println("Inner_Override");
}
};
}
class InnerFather {
InnerFather(int i) {
}
void print(){
System.out.println("InnerFather");
}
}
public static void main(String[] args) {
Outer o = new Outer();
InnerFather i = o.get_inner(10);
i.print();
}
}
可以通过构造代码块来实现匿名内部类的自定义的构造函数
abstract class Base {
public Base(int i) {
System.out.println("Base constructor");
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i){
{System.out.println("AnonymousConstructor constructor");}
public void f(){
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
}
}
(书上说,如果传入了新的对象,就比如下面例子中的s_in,这个s_in就必须是final的,但是我实验了一下发现并不用啊,我也没太搞懂。)
abstract class Base {
public Base(int i) {
System.out.println("Base constructor");
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i,String s_in){
return new Base(i){
{System.out.println("AnonymousConstructor constructor");}//构造代码块4.嵌套类
String s=s_in;
public void f(){
}
};
}
public static void main(String[] args) {
Base base = getBase(47,"hello");
}
}
四、嵌套类
嵌套类指的是被static修饰的内部类。这意味着:1.创建嵌套类对象不需要外部类对象。2.不能再嵌套类对象之中访问非静态的外围类对象。普通内部类的成员和方法只能放在类的外部层次上(这句话我没搞懂= =),所以普通内部类不能有static的成员和方法。但是嵌套类可以有。
public class Outer {
static class Inner{
static int i=5;
}
public static void main(String[] args) {
Inner i=new Outer.Inner();
}
}
可以从上面的例子看到,在创建这个嵌套类对象的时候,并没有像最开始那样,用一个外部类对象来创建这个内部类对象。其实这和静态方法差不多。
可以在接口内部定义内部类,而且他们即使没有static修饰,也会自动变成public 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();
}
}
}
书上有句话说的很好,在开发的时候建议在每个类中都写一个main方法测试,但是这又必须带着那些已经编译过的额外代码,所以我们可以用嵌套类放置测试代码。
public class Outer {
public void f(){
System.out.println("I need to be tested");
}
public static class Tester{
public static void main(String[] args) {
Outer o=new Outer();
o.f();
}
}
}
当然以上两段代码如果是在eclipse上运行的话,需要设置一下运行的main函数在哪,否则会报错
五、多层内部类嵌套
纸老虎,爱有几层有几层,反正只要是外部类的东西,不管哪层外部类,都能访问到。
public class Outer {
void f(){
System.out.println("hello");
}
class Inner1{
void g(){
System.out.println("java");
}
class Inner2{
void h(){
f();
g();
}
}
}
public static void main(String[] args) {
Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
in2.h();
}
}
下面是个好玩的
public class Outer {
void f(){
System.out.println("hello");
}
class Inner1{
void f(){
System.out.println("java");
}
class Inner2{
void h(){
f();
}
}
}
public static void main(String[] args) {
Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
in2.h();
}
}
最后打印结果是java。
大概就这么多吧,以后如果还有新东西再补。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。