常用关键字
this
在Java中,this关键字是一个重要且使用的关键字,使用this关键字可以做到:
- 调用本类中的属性
- 调用类中的方法
- 表示当前对象
让我们通过例子来具体分析一下:
private String name;
String getName(){
return name;
}
void setName(String name2){
name = name2;
}
在类Person中,因为我们使用了private类型的name,我们想要更改name的值必须传入一个新数据并赋值,我们通常使用不同的变量名,然后再进行赋值,比如name = name2;
但是为了增加代码可读性,并且保证程序正确,我们可以将这个方法中的语句更改为this.name = name;
在调用方法或构造方法时,可以与重载同时使用,如下所示:
class Person{
private String name;
Person(String name){
this.name = name;
}
Person(){
this("默认姓名");// this默认调用构造方法
}
}
通过以上重载,能够实现:如果创建对象时没有姓名,则给予一个默认姓名
(特别提示:在一个构造方法中使用this调用另一个重载构造方法时,调用语句必须在第一行,此为规定)
static
static,字面意思为静态的,在Java中也表示静态,static可以被用于修饰类中的成员变量和成员方法
被static关键字修饰的方法或变量会在类加载时被加载(在第6节中,被优先加载在方法区),可以直接访问,不需要依赖对象来访问或修改,且static修饰的属性永远只存在一份(即该属性公用,所有对象共同使用),在访问时,静态不能访问非静态,非静态可以访问静态(因为静态必然被加载,而非静态则要等待对象创建)
static的概念看起来有些复杂,但是如果理解了类的存储,实际上很好理解,这里我们就不举例子了,在之后的练习中再加深理解。
final
在定义一个变量时,我们使用变量去形容它,就是意味着在某些时候需要改变这个量,有些时候我们需要定义一个永远不变的常量,这时我们就需要使用final
final int NUM = 1;
使用final定义的量,无法更改,在类中声明时,必须直接赋值,在方法中,则可以且仅可以赋值一次
final定义的常量定义需要全部大写,单词之间用下划线_隔开,如TIMEOUT,PORT_NUMBER,DEFINED_TOTAL_AMOUNT
final也可以用于修饰类和方法,使用final定义的类不能被继承,final修饰的方法不能被子类重写(不是重载,重写在下面会被介绍)
如果一个属性同时被public,static,和final修饰,它被称为是一个全局常量
super
super是继承中重要的关键字,通过super,可以:
(继承在下面详细讲解,可以先跳过,看完继承再回来继续)
- 访问父类的构造方法
- 访问父类的属性
- 访问父类的方法
使用this方法能够调用本类中的变量和方法,使用super就能够调用父类中的变量和方法
class Father{
String lastName;
Father(){
System.out.println("Father类的构造方法被调用了");
}
void say(){
System.out.println("say方法被调用了");
}
}
class Son extends Father{
public Son(){
super.say();
}
String lastName = super.lastName;
}
而使用super在构造方法中调用构造方法时,同样需要把调用语句放在第一行(和this调用构造方法一样),所以不能在子类构造方法中同时使用super和this调用构造方法。
abstract
abstract关键词也和继承有关,abstract意为抽象,即为不能确定的,抽象可以被用于修饰类和方法:
abstract class 类名{
abstract void 方法名();
}
抽象类中可以有不抽象的方法,抽象方法必须写在抽象类或接口中
抽象方法不能有方法体,只能存在声明,等待子类重写,构造方法不能抽象
抽象类与类的区别在于,抽象类不能直接进行实例化,抽象类必须被子类继承,且继承的子类(如果此子类不是抽象类)必须重写抽象类的全部抽象方法
代码块
代码块指的是把一段代码包装成块,一般的代码块定义在方法中,通过如下方式使用:
// 普通声明变量
int a;
int b;
// 在代码块中声明变量
{
int c;
int d;
}
在代码块中定义的属性,无法在代码块之外调用
代码块中有三个特殊类型,构造代码块,静态代码块,和同步代码块(多线程中常用),这里我们详细解释一下前两者
构造代码块被定义在类中,随着对象的创建而执行,且执行在构造方法之前,通常可以用于输出对象创建成功的信息(因为构造方法如果存在重载,并不是每个构造方法都会执行)
静态代码块同样被定义在类中,即用static修饰的代码块,随着类的加载而执行,因为类只被加载一次,所以静态代码块只执行一次,通常用于指示资源加载完毕
static{
int a;
}
所以执行顺序可以整理出:
静态代码块(程序启动) -> 构造代码块(类的对象被创建) -> 构造方法(同运行于类的对象创建时)
继承和接口
继承是面向对象技术中非常重要的一环,下面让我们开始学习继承
继承
继承关系是指一个类通过继承的方式来使用另一个类中的变量和方法,其中被继承的类被称为父类,继承的类叫做子类,继承通过如下方式实现:
class 父类名{
}
class 子类名 extends 父类名{
}
在继承之后,父类的所有变量和方法都可以被子类对象直接调用(除了父类中private修饰的),当存在同名变量,同名同参方法时,优先使用子类的变量和方法
(特别注意:父类中如果存在含参的构造方法,则必须存在一个无参的构造方法,否则子类会报错)
注意,Java的继承只能有单继承,多重继承,没有多继承(多重继承如:A继承B,B继承C,A其实就可以使用C的变量和方法)
重写
重写(override)是可以发生在类的继承中的事件,在继承中我们 提到,当子类和父类中存在同名的属性或者同名同参的方法时,会优先调用子类中的属性或方法,其实这就是一个重写
class Father{
void say(){
System.out.println("say方法被调用了");
}
}
class Son extends Father{
@Override
void say(){
System.out.println("子类中say方法被调用了");
}
重写必须满足以下规则:
- 名称,参数列表及类型,返回类型,必须完全一致
- 重写的属性或方法的访问权限不能比父类的更低
- 父类的成员方法只能被子类重写
- 若有修饰符static或private,不能被重写
在方法前加上@Override可以检查是否为重写方法
接口
如果一个抽象类中全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义为一个接口:
interface 接口名称{
全局变量声明;
抽象方法1;
抽象方法2;
}
接口的使用有助于降低程序的耦合性(模块与模块之间的粘性),使程序的扩展和维护更轻松
在接口中,因为确定其中都是全局常量和抽象方法,所以不需要额外声明public,static,或final,其中的属性和方法会自动调整为全局常量和抽象方法
一个类可以多实现接口,也可以继承的同时实现多接口,并且接口本身还可以多继承:
class 子类 implements 父接口1,父接口2...{
}
class 子类 extends 父类 implements 父接口1,父接口2...{
}
interface A extends B,C{
}
接口中不能存在构造方法,也不能存在static或final修饰的方法(使用static并不会报错,且用了static后还可以写出具体的方法体,但是无法被重写和使用)
多态
多态指对象可以有多种表现形式,子类就可以被称之为父类的一种表现形式,并且可以用如下方式将对象的类型强制转化:
Son son = new Son();// 创建Son类的对象son
son.say();// 调用son对象的say方法
Father father = son;// 将Son类示例son变为Father类实例命名为father
Son son1 = (Son) father;// 将Father类实例father转化为Son类实例son1
(特别提示:和基础数据类型的转换一样,不改变原先的对象)
方法的重载和重写也是多态的一种,其中重载体现了一个类中方法的多态性,而重写体现了父子类中方法的多态性
可以通过instanceof方法验明对象是哪个类的实例:
boolean b = 需要判断的对象名 instanceof 类名;
如果此对象是该类(或其子类)的实例,则b值为true,反之则为false