Java面向对象-补充


        

访问修饰符

在Java中有以下四种访问修饰符:

  • default(默认):在同一个包内可见,不用任何修饰符。 使用对象:类、接口、变量、方法

  • private:在同一个类内可见。 使用对象:变量、方法 注意:不能修饰类(外部类)

  • public:对所有类可见。 使用对象:类、接口、变量、方法

  • protected:在同一包内的类与所有子类可见。 使用对象:变量方法 注意:不能修饰类(外部类)

访问修饰符.png

访问控制与继承:

- 父类中声明为 public 的方法在子类中也必须为 public。  

- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。  

- 父类中声明为 private 的方法,不能够被继承。  

其他修饰符

为了实现一些其他的功能,Java 也提供了许多非访问修饰符:

static 修饰符:用来修饰类方法和类变量。

final 修饰符:用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。

abstract 修饰符:用来创建抽象类和抽象方法。

synchronized 和 volatile 修饰符:主要用于线程的编程。

Static: 详细解析

Final:详细解析

内部类

在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

内部类的一些特性:

  1. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

  2. 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

  3. 创建内部类对象的时刻并不依赖于外围类对象的创建。

  4. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

  5. 内部类提供了更好的封装,除了该外围类,其他类都不能访问。

在Java中内部类主要分为成员内部类、局部内部类、匿名内部类和静态内部类

成员内部类

成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是 private 的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

在成员内部类中要注意两点,第一:成员内部类中不能存在任何 static 的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

代码实现:

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
package SomeTest;

public class MemberInnerClass {
private String name;

private void outerDisplay(){
System.out.println("outerClass->MemberInnerClass");
}
class InnerClass{

public void innerDisplay(){
// 使用外部类的属性
name = "Philxin";
System.out.println(name);
// 使用外部类的方法
outerDisplay();
}
}
// 推荐使用getXXXXX()来获取成员内部类,尤其是该内部类的构造函数无参时
public InnerClass getInnerClass(){
return new InnerClass();
}

public static void main(String[] args) {
MemberInnerClass outer = new MemberInnerClass();
MemberInnerClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
// 也可以通过下面的方式创建一个inner对象
// MemberInnerClass.InnerClass inner = new MemberInnerClass().new InnerClass();
}
}

演示结果:

1
2
Philxin
outerClass->MemberInnerClass

局部内部类

局部内部类,它是嵌套在方法和作用于内的,对于它的使用主要是应用与比较复杂的的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

代码实现:

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
package SomeTest;

interface Destionation{
void readLabel();
}
public class LocalInnerClass {

public Destionation destionation(String str) {
class PDestionation implements Destionation{
private String label;
public PDestionation(String whereTo) {
label = whereTo;
readLabel();
}
@Override
public void readLabel(){
System.out.println(label);
}
}

return new PDestionation(str);
}

public static void main(String[] args) {
LocalInnerClass pro = new LocalInnerClass();
Destionation d = pro.destionation("China");
}
}

演示结果:

1
China

静态内部类

使用 static 修饰的内部类我们称之为静态内部类,也可称作嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部内,但是静态内部类却没有。没有这个引用就意味着:

  1. 它的创建是不需要依赖于外部类的。

  2. 它不能使用任何外部类的非static成员变量和方法。

代码实现:

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
package SomeTest;

public class StaticOuterClass {
private String sex;
private static String name = "Philxin";
// 静态内部类
static class StaticInnerClass{
public static String name1 = "Philxin_staticInner";

public void display(){
/*
* 静态内部类只能访问外围类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OuterClass name = " + name);
}
}
class StaticInnerClass2{
// 非静态内部类不能存在静态成员
public String name2 = "Philxin_inner";
// 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的
public void display(){
System.out.println("OuterClass name = " + name);
}
}
// 外部类方法
public void display(){
// 外部类访问静态内部类,直接通过内部类访问
System.out.println(StaticInnerClass.name1);
// 静态内部类 可以直接创建实例不需要依赖于外部类
new StaticInnerClass().display();

// 非静态内部的创建需要依赖于外部类
StaticOuterClass.StaticInnerClass2 inner = new StaticOuterClass().new StaticInnerClass2();
// 访问非静态内部类的成员需要使用非静态内部类的实例
System.out.println(inner.name2);
inner.display();
}
public static void main(String[] args) {
StaticOuterClass outer = new StaticOuterClass();
outer.display();
}
}

演示结果:

1
2
3
4
Philxin_staticInner
OuterClass name = Philxin
Philxin_inner
OuterClass name = Philxin

匿名内部类(重点)

匿名内部类也就是没有名字的内部类

正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,

它的书写格式如下

1
2
3
new  父类构造器(参数列表) |  实现接口(){
// 匿名内部类的类体部分
}

使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有 class 关键字,这是因为匿名内部类是直接使用 new 来生成一个对象的引用。当然这个引用是隐式的。

代码实现:

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
package SomeTest;

abstract class Bird{
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public abstract int fly();
}
public class AnonymousInnerClass {
public void test(Bird bird){
System.out.println(bird.getName() + "能够飞" + bird.fly() + "m");
}
public static void main(String[] args) {
AnonymousInnerClass test = new AnonymousInnerClass();
// 匿名内部类中,入股希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是 final 的。
final int a = 1000;
test.test(new Bird() {
@Override
public int fly() {
return a;
}
@Override
public String getName(){
return "大雁";
}
});
}
}

演示结果:

1
大雁能够飞1000m

匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用。对于上面的实例,如果我们需要对 test() 方法里面内部类进行多次使用,建议重新定义类,而不是使用匿名内部类。

注意事项
在使用匿名内部类的过程中,我们需要注意如下几点:

  1. 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。

  2. 匿名内部类中是不能定义构造函数的。

  3. 匿名内部类中不能存在任何的静态成员变量和静态方法。

  4. 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。

  5. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

参考

---------------- The End ----------------

本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布
本文地址:https://philxin.top/2019/10/04/Java面向对象-补充/
转载请注明出处,谢谢!

0%