Java中的包与类(2)-内部类
小tips:本文可能会缺乏一些关于类与对象更基础的知识点,如果你需要可以访问我的知乎:
Java中的包与类(2)
Java中的内部类
什么是类,什么是对象
面向对象的程序设计过程有两个重要概念:类和对象。对象是一个具体存在的实体,例如我们口中所说的人其实都是人类的实例,人类就是人的实例的抽象概念,即对象是类的实例。类中至少包括了类的成员变量和方法。比如在人类这个类中,头就是人类的成员变量,呼吸就是人类的方法。关于类与对象在下一篇文章中阐述。
类与对象在内存空间的情况
从OneCow
类的定义来看,这个类包含两个实例变量,变量是需要内存来存储的。因此,当创建OneCow
对象时,必然需要有对应的内存来存储。OneCow one = new OneCow();
这一行代码实际上创建了两个东西,一个变量one
,一个实例化的OneCow
类。one中包含一个指向OneCow
的指针。只不过这个指针你无法像C那么灵活地去运算。
1 |
|
运行代码可知最后输出地是22,这很自然,因为OneCow two = one;
这段代码你以为是复制一个实例给two?其实并不是,只不过是two和one现在都拥有了同样的指针,同样指向了内存中的OneCow
实例而已。
内部类
关于内部类的概念和一些代码可以看我之前的文章:内部类
这里重点关于内部类的作用域的问题。
1 |
|
假设上面的代码是处于一个记事本中,但他们是互相独立的,没有谁是谁的内部类这种说法,内部类一定是放在另一个类的类体也就是花括号中的才算数。
内部类可以访问外部类的private属性或方法
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57public class Cow {
private double weight;
//外部类的两个重载的构造器
public Cow(){}
public Cow(double weight){
this.weight = weight;
}
//定义一个非静态内部类
private class CowLeg{
//非静态内部类的两个实例变量
private double length;
private String color;
//非静态内部类的两个重构的构造器
public CowLeg(){}
public CowLeg(double length,String color){
this.length = length;
this.color = color;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//非静态内部类的实例方法
public void info(){
System.out.println("当前牛腿颜色是:"
+color + ",高:" + length);
//直接访问外部类的private修饰的成员变量
System.out.println("本牛腿所在的奶牛重:"+weight);
}
}
public void test(){
CowLeg blackAndWhite = new CowLeg(1.12, "黑白相间");
blackAndWhite.info();
}
public static void main(String[] args) {
Cow cow = new Cow(378.9);
cow.test();
}
}从上面的程序编译以后可以得到它的l两个class文件一个为
Cow.clss
另一个为Cow$CowLeg.class
,运行的方法也非常简单,直接java Cow
就行。编译运行以后你可以发现内部类可以直接访问外部类的私有变量private double weight;
内部类可以有和外部类一样的属性名字,当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果不存在,则到该方法的内部类中寻找,如果还是不存在就去外部类中寻找。
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
28public class DiscernVariable {
private String prop = "外部类的实例变量";
private class InClss
{
private String prop = "内部类的实例变量";
public void info(){
String prop = "局部变量";
//通过外部类类名.this.varName访问外部类实例变量
System.out.println("外部类的实例变量值:"+DiscernVariable.this.prop);
//通过this.varName 访问内部类实例变量
System.out.println("内部类的实例变量值:"+this.prop);
//直接访问局部变量
System.out.println("局部变量的值:"+prop);
}
}
public void test(){
InClss inClss = new InClss();
inClss.info();
}
public static void main(String[] args) {
new DiscernVariable().test();
}
}非静态内部类里不能有静态方法、静态成员变量、静态初始化块
1
2
3
4
5
6
7
8
9
10
11
12
13public class InnerNoStatic{
private class InnerClass{
/*
下面三个静态声明都将引发如下编译错误:
非静态内部类不能有静态声明
*/
static{
System.out.println("=======");
}
private static int inProp;
private static void test(){}
}
}当你创建一个子类时,子类构造器总会调用父类的构造器,因此在我们创建非静态的内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象。这样做很合理,我们调用内部类的时候,如果他不是静态的,就需要先有一个外部类的实例。
当通过实现接口来创建匿名内部类时,匿名内部类不能显式地定义构造器,因此匿名内部类只有一个隐式地无参数构造器,故new接口名后地括号里不能传入参数值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24interface Product{
double getPrice();
String getName();
}
public class AnonymousTest{
public void test(Product d){
System.out.println("购买了一个"+d.getName()+",花掉了"+d.getPrice());
}
public static void main(String[] args){
AnonymousTest ta = new AnonymousTest();
//调用test()方法时们需要传入一个Product参数
//此处传入其匿名实现类的实例
ta.test(new Product(){
public double getPrice(){
return 567.8;
}
public String getName(){
return "AGP显卡";
}
});
}
}但如果通过继承父类来创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参列表。
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
44
45
46
47
48
49
50
51
52
53
54abstract class Device{
private String name;
public abstract double getPrice();
public Device(){}
public Device(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class AnonymousInner {
public void test(Device d){
System.out.println("购买了一个"+d.getName()+",花掉了"+d.getPrice());
}
public static void main(String[] args) {
AnonymousInner anonymousInner = new AnonymousInner();
//调用有参构造器创建Device匿名实现类的对象
anonymousInner.test(new Device("电子示波器") {
public double getPrice() {
return 67.8;
}
});
//调用无参构造器创建Device匿名实现类的对象
Device device = new Device(){
//初始化块
{
System.out.println("匿名内部类的初始化块...");
}
//实现抽象方法
public double getPrice(){
return 56.2;
}
//重写父类的实例方法
public String getName(){
return "键盘";
}
};
anonymousInner.test(device);
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!