面向对象基础
继承
-
构造子类方法时必须加上
super();
括号内参数就是父类构造方法所需参数class Student extends Person { protected int score; public Student(String name, int age, int score) { super(name, age); // 调用父类的构造方法Person(String, int) this.score = score; } }
-
在子类的覆写
(override)
方法中,如果要调用父类的被覆写的方法,可以通过super
来调用。例如:class Person { protected String name; public String hello() { return "Hello, " + name; } } class Student extends Person { @Override public String hello() { // 调用父类的hello()方法: return super.hello() + "!"; } }
final
final
关键字保证子类不能override
父类的方法:
e.g. public final String hello()
- 还可以
final
直接规定不可继承父类
e.g. final class person{}
- 对于一个类的实例字段,同样可以用
final
修饰。用final
修饰的字段在初始化后不能被修改。
e.g. public final String name = "Unamed";
- 对
final
字段重新赋值会报错:
Person p = new Person();
p.name = "New Name"; // compile error!
抽象类
如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法:
class Person {
public abstract void run();
}
-
这是一个抽象方法,只需要声明,不用执行语句
-
正确编译需要将父类声明为
abstract
abstract class Person{ public abstract void run(); }
-
抽象类无法实例化,也就是不能创建对象
Person p = new Person(); // 编译错误
-
抽象类只能用于继承
面向抽象编程
当我们定义了抽象类Person
,以及具体的Student
、Teacher
子类的时候,我们可以通过抽象类Person
类型去引用具体的子类的实例:
Person s = new Student();
Person t = new Teacher();
interface 接口
在Java中,使用interface
可以声明一个接口:
interface Person {
void run();
String getName();
}
-
所谓
interface
,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract
的,所以这两个修饰符不需要写出来(写不写效果都一样)。 -
当一个具体的
class
去实现一个interface
时,需要使用implements
关键字。class Student implements Person {...}
-
我们知道,在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个
interface
,例如:class Student implements Person, Hello { // 实现了两个interface ... }
- 降低类之间的耦合度
- 避免单继承的限制
接口继承
- 一个
interface
可以继承自另一个interface
。interface
继承自interface
使用extends
,它相当于扩展了接口的方法。
静态字段与静态方法
静态字段
浅显理解:不管多少个对象,公用一个静态字段,一个变全变
- 静态字段是属于类而不是对象的,所有实例共享一个静态字段
- 对静态字段的访问,好的方法是
类名.静态字段
,不推荐用实例变量.静态字段
去访问静态字段
静态方法
调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。静态方法类似其它编程语言的函数。例如Person.run()
- 因为静态方法属于
class
而不属于实例,因此,静态方法内部,无法访问this
变量,也无法访问实例字段,它只能访问静态字段。
接口的静态字段
因为interface
是一个纯抽象类,所以它不能定义实例字段。但是,interface
是可以有静态字段的,并且**静态字段必须为final
**类型:
public interface Person {
public static final int MALE = 1;
public static final int FEMALE = 2;
}
实际上,因为interface
的字段只能是public static final
类型,所以我们可以把这些修饰符都去掉
作用域
1. public
-
public
类,可以被任何其他类访问,甚至不是同一个package
package abc; public class Hello { public void hi() { } }
上面的
Hello
是public
,因此,可以被其他包的类访问:package xyz; class Main { void foo() { // Main可以访问Hello Hello h = new Hello(); } }
但是,定义为
public
的field
、method
可以被其他类访问,前提是首先有访问class
的权限:
2. private
- 定义为
private
的field
、method
无法被其他类访问 - 由于Java支持嵌套类
nested class
,如果一个类内部还定义了嵌套类,那么,嵌套类拥有访问private
的权限.
3. protected
protected
作用于继承关系。定义为protected
的字段和方法可以被子类访问,以及子类的子类
4. default
同一个包内正常访问
内部类
1. Inner class
class Outer {
private String name;
Outer(String name) {
this.name = name;
}
class Inner {
void hello() {
System.out.println("Hello, " + Outer.this.name);
}
}
}
在new
一个新的Inner
对象时,要实例化一个Inner
,我们必须首先创建一个Outer
的实例,然后,调用Outer
实例的new
来创建Inner
实例:
Outer outer = new Outer("Nested"); // 实例化一个Outer
Outer.Inner inner = outer.new Inner(); // 实例化一个Inner
- Inner Class和普通Class相比,除了能引用Outer实例外,还有一个额外的“特权”,就是可以修改Outer Class的
private
字段,因为Inner Class的作用域在Outer Class内部,所以能访问Outer Class的private
字段和方法。
2. 匿名类
匿名类就是没有使用class
关键字声明定义的类,也就相当于并没有给这个类启用一个可以全局调用的名字
- 不完全理解
3. 静态内部类(Static Nested Class)
class Outer {
private static String NAME = "OUTER";
private String name;
Outer(String name) {
this.name = name;
}
static class StaticNested {
void hello() {
System.out.println("Hello, " + Outer.NAME);
}
}
}
用static
修饰的内部类和Inner Class有很大的不同,它不再依附于Outer
的实例,而是一个完全独立的类,因此无法引用Outer.this
,但它可以访问Outer
的private
静态字段和静态方法。如果把StaticNested
移到Outer
之外,就失去了访问private
的权限。
内部类的优势在于,可以访问外部类及其父类的方法和属性。因为java的类只能继承自一个父类,通过内部类,相当于可以同时继承外部类的父类和自己的父类,也就是继承两个父类。
匿名内部类简化了内部类的继承与创建对象的写法
通过 new SuperClass() {...}
等同于创建了一个继承自SuperClass父类的匿名子类的对象。