将一个类的定义放在另一个类的内部,这就是内部类。
内部类拥有外部类对象的引用。
在一个类中可以有多个内部类,以不同的方式实现同一个接口,或者继承同一个类。
有了内部类,一个类可以有任意多种方式实现任意多个接口,可以有任意多种方式继承任意多个类。
final关键字主要的含义就是“无法改变”。final可以用于数据、方法和类。
final作用于数据上表示数据本身不可以改变。1
2
3
4
5
6
7
8final int a = 10;
a = 11; // 错误
static final int C = 2; // 编译期常量
final List<String> list = new ArrayList<String>();
list.add("a"); // 正确
list.add("b"); // 正确
list = new ArrayList<String>(); // 错误,list不能指向其他对象
如上,final作用于引用表示引用值本身不能变,即不能指向其他对象。
在方法体的匿名内部类中,参数需要用final修饰。1
2
3
4
5
6
7
8
9
10
11interface adder{void addXYZ();}
public class outer{
public adder getAdder(final int x){
final int y = 10;
return new adder(){
int z = 10;
@Override
void addXYZ(){return x + y + z;}
}
}
}
访问权限控制主要是为了解决类库开发的问题,类库的代码往往需要重构,但是类库的使用者却需要代码保持不变,为此,对于类库中的代码,使用者的访问应该是受限制的,他应该只能访问部分需要公开的代码,比如所谓的API。
因此程序代码需要约定代码的访问权限。在java中,访问权限从大到小为:public, protected, 包访问权限(没有关键词), private. 其中包是库的基本单元。
包是通过名字空间组织的一组类。
通过包可以很方便的把实现某一功能的类组织起来,在类文件(.java)中通过 package package_name
指定类所在的包,通过import
来导入。比如import java.util.ArrayList
导入java.util
包下的ArrayList
类。
接口和内部类提供了很好的接口与实现分离的方法。
在多态中,一个方法操作的是类,那么你可以使用这个类及其子类,代码会有很好的复用性。但是对于不在这个继承结构中的某个类,就没有办法了。
而接口却可以放宽这种限制。
多重继承实际上就是组合多个类的接口。1
2// B为抽象类或基类,C1,...为接口
class A extends B implements C1, C2, C3 ...
则如上A可以向上转型为B, C1, C2 …, 因此可以很方便的复用代码
接口最大的用处就是一个接口可以有很多不同的实现。于是如果一个方法以一个接口类型为参数,则使用者可以通过改变接口的实现方式和传入的对象,来产生不同的行为。
比如Java中的Scanner类,它的构造器接收的是一个Readable接口。如果创建了一个新的类,想让Scanner作用于它,只需实现Readable接口。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43//: interfaces/RandomWords.java
// Implementing an interface to conform to a method.
import java.nio.*;
import java.util.*;
public class RandomWords implements Readable {
private static Random rand = new Random(47);
private static final char[] capitals =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers =
"abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels =
"aeiou".toCharArray();
private int count;
public RandomWords(int count) { this.count = count; }
public int read(CharBuffer cb) {
if(count-- == 0)
return -1; // Indicates end of input
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i = 0; i < 4; i++) {
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
return 10; // Number of characters appended
}
public static void main(String[] args) {
Scanner s = new Scanner(new RandomWords(10));
while(s.hasNext())
System.out.println(s.next());
}
} /* Output:
Yazeruyac
Fowenucor
Goeazimom
Raeuuacio
Nuoadesiw
Hageaikux
Ruqicibui
Numasetih
Kuuuuozog
Waqizeyoy
*///:~
如果某个类没有实现Readable接口,那应该怎么办呢?只需extends,并实现Readable接口即可。其实就是一个适配器,适配Readable接口。
1 | //: interfaces/RandomDoubles.java |
为RandomDouble 适配Readable接口1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//: interfaces/AdaptedRandomDoubles.java
// Creating an adapter with inheritance.
import java.nio.*;
import java.util.*;
public class AdaptedRandomDoubles extends RandomDoubles
implements Readable {
private int count;
public AdaptedRandomDoubles(int count) {
this.count = count;
}
public int read(CharBuffer cb) {
if(count-- == 0)
return -1;
String result = Double.toString(next()) + " ";
cb.append(result);
return result.length();
}
public static void main(String[] args) {
Scanner s = new Scanner(new AdaptedRandomDoubles(7));
while(s.hasNextDouble())
System.out.print(s.nextDouble() + " ");
}
} /* Output:
0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964
*///:~
类的成员如果没有指定会默认初始化,基本类型初始化为默认值,引用初始化为null
。也可以通过定义显示初始化。1
2
3
4
5
6
7
8
9
10
11
12
13public class InitialValues {
boolean bool = true;
boolean bool1; // 默认为 false
char ch = 'x';
char ch1; // 默认初始化为 空
byte b = 47;
short s = 0xff;
int i = 999;
long lng = 1;
float f = 3.14f;
double d = 3.14159;
String a; // 默认初始化为null
} ///:~