Summary
Java是面向对象的语言,应用Java就要深入理解并掌握Java中类的定义、继承、访问控制、修饰符和接口等有关面向对象的内容。
- 类的组成、初始化和调用
- 类的继承
- 包
- 修饰符
- 接口
类的组成、初始化和调用
提到面向对象语言,直接想到的是类的概念,类是把对象抽象出来形成一类对象的想象,类封装了一类对象的状态和方法。类包含field和method。
field中文叫做字段、域、域变量、属性、成员变量等,它是类的属性,通过变量来表示;method中文叫做方法,它是类的功能和操作,通过函数来表示。
作者语:类就像现实物品的一个分类,比如鞋、衣服,它使得我们能够更加高效的沟通,不仅在现实生活的对话中,也在编程的代码间。
难以想象我们现实生活中的对话是:“请帮我拿一下那边红色的用来穿在脚上走路的物品”(请帮我拿下那边红色的鞋),所以写程序要用好类的概念。
类可以实例化,也就是建立一个具体的对象,这个时候需要初始化(通常用关键字new),Java是通过构造方法constructor完成的。构造方法和类名是同名的,且不写返回值。
class Person{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
}
如果类没有写构造方法,则系统生成默认构造方法(default constructor)。
class Person{
String name;
int age;
//Person(){},这是系统生成的默认构造方法,编译时会补充。
}
初始化并使用对象,Person类新建一个对象p,输出p的名字,如下:
Person p = new Person();
System.out.println(p.name);
扩展:
1.如果多个方法有相同的名字,编译时可以根据方法的签名signature(参数类型和个数)识别出,即Java有方法重载overloading的能力,体现了面向对象语言的多态polymorphism。下面这段程序sayHello有两个方法,运行结果是:
Hello! My name is Xiaoming
Hello Xiaohong! My name is Xiaoming
public class Example{
public static void main(String[] argv){
Person p1 = new Person("Xiaoming", 18);
Person p2 = new Person("Xiaohong", 14);
p1.sayHello();
p1.sayHello(p2);
}
}
class Person{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
void sayHello(){
System.out.println("Hello! My name is " + name);
}
void sayHello(Person another){
System.out.println("Hello " + another.name + "! My name is " + name);
}
}
2.在上述程序的构造方法中出现了关键词this,它的作用是引用字段field,添加它的目的是区分字段和局部变量。比如第一段程序构造函数中有这样一句代码:this.name = name;
this.name代表Person的字段name,而等号后面的name是构造方法的参数变量name。
类的继承
面向对象的三大核心特征是封装、多态和继承,在上一节中提到了封装和多态,这一节要谈继承。
说到继承,至少涉及两个对象,称为子类subclass和父类superclass。Java规定只能单继承,一个类只能有一个直接父类。继承符合DRY(Don't repeat yourself)原则,如果子类有和父类一致的字段或者方法,那么直接继承,不要写重复的代码。Java的继承是通过关键词extends来实现的,沿用上文Person的代码,如下:
class Student extends Person{
String teacher;
int grades;
Student(String teacher, int grades, String name, int age){
super(name, age);
this.teacher = teacher;
this.grades = grades;
}
boolean isGood(){return grades > 80;}
}
subclass能继承superclass的所有字段和非private方法,但不能继承superclass的构造方法。JDK1.5后可以用@Override标记来表示subclass对superclass同名方法的覆盖override。
上述程序的构造方法中出现了关键词super,它的作用是引用父类的字段和方法。
作者语:继承是面向对象语言中容易混乱的部分,尤其是多重继承的时候,假设A继承于B,B继承于C,而C如果又继承于A,这就是个死循环。Java单继承的规定在一定程度上增强了安全性。
包
包package的出现是为了解决名字空间和名字冲突,一方面包是名字空间和存储路径,另一方面也规定了访问性,比如同一个包中默认情况可互相访问。注:包与继承没有关系,一个superclass只要是public的,子类可以在不同package中继承superclass。
import语句可以导入包,基本语法是:
import package1[.package2...].classname;
例如:import java.util.Date;
作者语:包可以理解为OS里的文件夹。
修饰符
修饰符modifier分为两类:访问修饰符access modifier和其他修饰符。modifer可以修饰类和类的成员(field和method)。
1.访问修饰符
| | 同一个类中 | 同一个包中(包括子类) | 不同包中子类 | 不同包中非子类 |
|:--- :|:-----------:|:----------:|:-------------: |:-------------: |
|private| Yes | | | |
|默认(包可访问)| Yes | Yes | | |
|protected| Yes | Yes | Yes | |
|public| Yes | Yes | Yes| Yes |
private只能在同一个类中访问,可以更好的将信息进行封装和隐藏,存取时使用set和get方法;
public class Person2{
private int age;
public void setAge(int age){
if(age>0 && age <150){
this.age = age;
}
}
public int getAge(){
return age;
}
}
默认是class前面不加修饰符,默认同一个包和类可以访问;
protected只是不允许不同包当中的非子类访问;
public的作用是任何包中都可以调用。
作者语:访问权限由严格到宽松大体流程是,从最严格只能在同一个类中访问的private开始,到同一个包中可以访问的默认修饰,再到宽松一些可以在不同包的子类中调用的protected修饰,最后是最宽松的在任何包中都可以调用的public修饰。
2.其他修饰符
基本含义 | 修饰类 | 修饰成员 | 修饰局部变量 | ||
---|---|---|---|---|---|
static | 静态的、非实例的、类的 | 可以修饰内部类 | Yes | ||
final | 最终的、不可改变的 | Yes | Yes | Yes | |
abstract | 抽象的、非实例的 | Yes | Yes |
static字段只属于类,不属于任何对象实例,例如:定义Person类,其中定义一个统计人数的参数,并不属于任何一个对象实例,
class Person{
static int totalNumber;
String name;
int age;
Person(String n, int a){
name = n;
age = a;
}
}
static方法是属于整个类的方法,不属于某个实例,不能操纵处理某个实例的成员变量;
final修饰的类不能被继承,也就是说不能有子类,final修饰的方法是不能被子类覆盖的方法,final修饰的字段是只读的不能修改;
abstract修饰的类不能实例化,abstract修饰的方法是抽象方法,为所有子类定义统一接口,只需声明,格式如下:
abstarct returnType abstractMethod([paramlist]);
接口
接口interface是某种特征的约定,它也是面向对象编程思想的核心组成部分。
作者语:比如,我们把现实中的飞机写成一个类,其中的战斗机、运输机都是飞机这个类的子类,有自己的特征。战斗机中,歼击机10是歼击机9的新一代,我们说歼击机10继承了歼击机9,在歼击机9的动力系统基础上,歼击机10开发了应急情况另一个加速系统,也就是说有两个动力系统方法,一个是继承歼击机9,另一个是应急下新增加的动力系统,这两个就是多态的应用。
除了飞机外,天空中还有鸟。鸟和飞机两个类都会写一个特征——它们能够离开地面XX米,且有自主控制能力……本着DRY的原则,这里需要优化,接口能很好的解决这个问题,我们可以写一个特征“飞”的接口,飞机和鸟以及其他能飞的物体都可以使用这个接口。
根据接口的定义,它的modifier默认是public+abstarct,因为接口的出现就是要让其他类使用,所以默认是public的;而接口本身就是特征的约定,不是实例化的,所以默认是abstract的。且接口是可以多继承的,与类的继承不一样,甚至有人会说面向对象的编程实质上是“面向接口的变成”,可见接口在面向对象语言中的重要性。
作者语:Java规定类是单继承,而接口在某种程度上说可以打破这个限制,接口不关注类之间的层次,可以直接使用某个特征方法函数。
接口的定义一般如下:
[public] interface InterfaceName [extends listOfSuperInterface]{
returnType methodName([paramlist]);
}
如果定义中没有public声明,则只能被同一个包中的类访问;
extends继承部分与类的继承语法一致,不同的是接口可以多重继承,用逗号隔开即可;
接口中只进行方法的声明,不提供具体实现,所以只有方法体,用“;”结束,这里的方法具有public和abstract属性。
接口的实现用implements子句
class className implements interfaceName{
returnType methodName([paramlist]){
//写接口中所声明方法的实现
}
}
接口中定义的常量具有public, static, final的属性,一般大写名字:
type NAME = value;
下面的代码用接口定义了人
interface Runner(){public void run();}
interface Swimmer(){public void swim();}
interface Flyable(){
abstract public void fly();
public void land();
public void takeoff();
}
abstract class Animal{
int age;
abstract public void eat();
}
class Person extends Animal implements Runner, Swimmer, Flyable{
public void run(){System.out.println("run");}
public void swim(){System.out.println("swim");}
public void fly(){System.out.println("fly");}
public void land(){System.out.println("land");}
public void takeoff(){System.out.println("takeoff");}
public void eat(){System.out.println("eat");}
}
public class Test{
public static void main(String[] args){
Test t = new Test();
Person p = new Person();
t.m1(p);
t.m2(p);
t.m3(p);
t.m4(p);
}
public void m1(Runner r){r.run();}
public void m2(Swimmer s){s.swim();}
public void m3(Flyable f){f.fly(); f.land(); f.takeoff();}
public void m4(Animal a){a.eat();}
}
To be continued
Java完整的源文件格式如下:
package packageName//指定文件中的类所在的包,0/1个
import packageName.[className]; //指定引入的类,0/多个
public class classDefinition //属性为public的类定义,0/1个,名字必须与文件名一致
{
[public] interface InterfaceName [extends listOfSuperInterface]//接口的定义
{
type constantName = value; //接口常量声明,默认是public, static, final的
returnType methodName([paramlist]); //接口方法声明,没有方法体
}
[public] [abstract|final] class className [extends superClassName] [implements InterfaceNameList] //类的声明
{
[public|protected|private] [static] [final] type variableName; //成员变量声明
[public|protected|private] [static] [final] returnType methodName([paramlist]) [throws exceptionlist] //方法声明及实现
{
statement;
}
}
}
有三种方法要求固定的声明方式:
- 构造方法
className([paramlist]){
statements;
}
- main方法
public static void main(String[] args){
statements;
}
- finalize方法
protected void finalize() throw throwable{
statements;
}