class Type{
public String _var; // 成员属性
public Type(...){ // 构造方法
// ...
}
public void method)(...){ // 成员方法
// ...
}
}
在 Java 中,public、private、protected 这些访问权限必须直接修饰方法,而不是 C++ 分类式地声明。
class Type{
public int field;
public void method(){
//...
}
}
Java 中有四种权限修饰方式:
修饰符 | 访问范围 |
---|---|
public | 均可访问 |
protected | 包外非子类无法访问 |
(缺省) | 包外均无法访问 |
private | 仅本类访问 |
用于对数据进行访问保护。
一般情况都这样写:
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
bool 比较特别:
public boolean isMale() {
return te;
}
public void setMale(boolean male) {
this.amle = male;
}
导入类:
import top.gaolihai.Type;
类的作用域在整个包内,故若与某类在同一个包,可以不导入,直接使用。
Type obj = new Type();
class Type {
static {
// ...
}
}
首次使用该类时(不论以何种方法),会直接调用静态代码块。
相当于对静态成员的构造函数。
关键字:extends
class Son extends Father {
// ...
}
super
关键字:super
子类构造隐式调父类的默认构造。super()
当不存在默认构造时,需要手动调用,且必须为第一个语句:
class Son extends Father {
public Son (int param) {
super(param); // 手动调 super
// ...
}
public void method() {
super.field;
super.method();
// ...
}
}
可以访问到所有父辈类的 constructor、method 及 field。
另外地,也可以通过this
调用本类构造:
用于为构造函数提供默认值(Java 中没有默认参数)。
class Type {
public Type() {
this(10);
}
public Type (int param) {
// ...
}
}
重写父类方法,实现动态多态。也叫(覆盖,覆写)
!!! 注意:
为防止寻址超出范围,子类返回值不允许是父类返回值的父辈类。
C++ 允许这样做,但不保证安全,所以 Java 禁止了。
为防止发生多态时无法访问子类重写变为 pirvate 的方法,Java 禁止子类用 private 方法重写父类的 public 方法。
C++ 同样允许这样做,但当试图访问不可访问的方法时,编译出错。
Java 允许访问范围较大的重写访问范围较小的,具体表现为:
public
> protected
> (默认)
> private
还要注意的是,父类的 private 方法无法被重写。在子类写同名方法不会出错,但这不是重写,而是一个新方法。
class Father {
public void method() {
// ...
}
}
class Son extends Father {
public void method() {
// ...
}
}
推荐使用注解:
@override
用于检测是否发生了正确的重写,是一种安全检测手段。
注解后若未正确重写会出现编译错误。
class Son extends Father {
@override
public void method() {
// ...
}
}
@Override
- 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。@Deprecated
- 标记过时方法。如果使用该方法,会报编译警告。@SuppressWarnings
- 指示编译器去忽略注解中声明的警告。@Retention
- 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。@Documented
- 标记这些注解是否包含在用户文档中。@Target
- 标记这个注解应该是哪种 Java 成员。@Inherited
- 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)@SafeVarargs
- Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。@FunctionalInterface
- Java 8 开始支持,标识一个匿名函数或函数式接口。@Repeatable
- Java 8 开始支持,标识某注解可以在同一个声明上使用多次。抽象类中可以存在抽象方法:
abstract class Father {
abstract void method();
}
与 C++ 不同,抽象类必须直接使用abstract
修饰。才允许定义抽象方法。
子类重写父类抽象方法:
class Son extends Father {
void method() {
// ...
}
}
接口是多个类的公有规范
关键字:interface
、implements
、default
由于接口仅是规范,其中的方法均为抽象方法,且不存在构造方法和静态代码块。
接口可以包含这些内容:静态常量、抽象方法、默认方法(Java 8)、静态方法(Java 8)、私有方法(Java 9)
默认方法用于方便地进行**接口升级**。
静态方法仅允许通过接口直接调用,防止出现命名冲突。
定义一个接口:
其中的方法会被隐式修饰为public abstract
,变量会被隐式修饰为public static final
interface _Interface {
// 静态变量
public static final int field;
// 抽象方法
public abstract void method();
// 默认方法
public default void defaultMethod() {
// ...
}
// 静态方法
public static void staticMethod() {
// ...
}
// 私有方法
private void privateMethod() {
// ...
}
private static void privateStaticMethod() {
// ...
}
}
接口的实现:
class specific implements _Interface{
@Override
public void method() {
// ...
}
// ...
}
接口允许继承且允许多继承:
interface _Interface extends _Interface1, _Interface2 {
// ...
}
前面提到,Java 为了防止出现二义性的问题,不允许类的多继承。
而接口都是抽象的,由开发者来实现,那么也就不存在多继承二义性的问题。
(对于默认方法的二义性,多重继承时会被要求必须重写冲突的默认方法)
interface _Interface1 {
public default void method() {
// ...
}
}
interface _Interface2 {
public default void method() {
// ...
}
}
public interface _Interface extends _Interface1, _Interface2 {
@Override
default void method() {
_Interface1.super.method();
}
}
一个类可以同时继承类和实现接口:
且在发生冲突时默认调用继承来的父类的方法。
在 Java 中,继承较实现接口更优先一些。
public Son extends Father implements _Interface1 {
// ...
}
多态的抽象表述:接口与实现的分离。
具体一些可以称:父类指针(引用)指向子类对象。
为了访问安全性,Java 不允许父类对象(实际上的)向下转型。会抛出ClassCastException
异常。
instanceof
判断实例关键字:instanceof
返回一个 boolean
值,表示前边的对象是否是后边类型的实例。
obj instanceof Type;
if (obj instanceof Son) {
((Son) obj).specificMethod();
}
其他的内容与 C++ 基本一致,不赘述。
在类内部定义类:
成员内部类允许使用各种权限修饰符。
class Outer {
//...
class Inner { // 成员内部类
//...
}
//...
}
注意,内部类不能存在静态声明。
实例化:
Outer.Inner obj = new Outer().new Inner();
内部类可以随意访问外部类的内容:
class Outer {
int field;
class Inner { // 内部类
int field;
void method() {
Outer.this.field; // 通过外部类名.this 访问
}
}
}
即方法内部的类:
局部内部类不允许使用任何修饰符,因为没有意义,仅当前方法的作用域可以完全访问。
class Outer {
//...
public void method() {
//...
class Inner { // 局部内部类
//...
}
//...
}
//...
}
注意,局部内部类对当前方法作用域的访问是受限的,它仅可访问final
或effectively final
的变量。必须保证内部类访问到的外部变量没有被实际改变过。
effectively final
即 “最终有效 final” 。
这是由于,当前方法栈出栈后,栈变量也随即释放。故欲访问当前作用域,必须保证欲访问的变量是一个常量。
对于一个接口:
interface _Interface {
void method();
}
我们可以在方法内直接实例化一个匿名内部类:
需要实现接口的所有方法。
_Interface obj = new _Interface() {
@Override
public void method() {
//...
}
};
或者直接调用方法:
new _Interface() {
@Override
public void method() {
//...
}
}.method();