Java面向对象——基础
1. 继承——extends
一个class只能继承一个类,即有且仅有一个父类;但一个父类可以被很多子类继承。
- 父类
Person
中的name
和age
属性不需要在子类Student
中重复定义 protected
可以将字段或方法的访问权限控制在了继承树内,比private
更适合- 这里如果
Person
类中的name
字段定义的是private
,那Student
类中的name
将会报错
- 这里如果
public class Main {
public static void main(String[] args){
Student stu = new Student();
stu.hello(); //unnamed
}
}
public class Person {
protected String name = "unnamed";
private int age = 0;
}
public class Student extends Person {
public void hello(){
System.out.println(name); //父类Person的name字段,即super.name
}
}
- 向上转型没问题,向下转型时为了避免转型出错,最好通过
A instanceof B
来判断是否成功
Person p = new Student();
if (p instanceof Student) {
// 只有判断成功才会向下转型:
Student s = (Student) p; // 一定会成功
}
2. 多态——@override
利用多态,totalTax()
只需要和Income
的getTax()
打交道就行了,完全不需要知道Salary
和Grey
的存在,也就是说如果要新增/删除一种收入,只需要让它extends Income
,然后@override
覆写getTax()
方法即可。
- Tips:用
final
修饰的方法/类/字段,不能被Override
。final
修饰符有多种作用:final
修饰的方法可以阻止被覆写;final
修饰的class可以阻止被继承;final
修饰的field必须在创建对象时初始化,随后不可修改。
public class Main {
public static void main(String[] args){
Income[] incomes = {
new Income(1000),
new Salary(10000),
new Grey(5000)
};
System.out.println("总纳税:" + totalTax(incomes));
}
public static double totalTax(Income... incomes){
double sumTax = 0.0;
for(Income income:incomes){
sumTax += income.getTax();
}
return sumTax;
}
}
/*
普通收入
*/
class Income{
protected double income;
public Income(double income){
this.income = income;
}
public double getTax(){
return income * 0.1; //普通收入纳10%的税
}
}
/*
工资收入
*/
class Salary extends Income{
public Salary(double income){
super(income);
}
@Override
public double getTax() {
if(income<=5000){ //[0,5000]不纳税
return 0;
}else{ //超出5000的部分纳10%的税
return (income-5000) * 0.1;
}
}
}
/*
灰色收入
*/
class Grey extends Income{
public Grey(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
总纳税:600.0
3. 抽象类——abstract
抽象类只能用于被继承,其强迫子类实现其抽象方法,并且这个抽象方法必须没有执行代码。
案例:Holiday
类如果继承Travel
抽象类,那必须要实现buyTickets()
这个抽象方法。
public class Main {
public static void main(String[] args){
Holiday holiday = new Holiday();
holiday.buyTickets();
}
}
/*
抽象类 Travel
*/
abstract class Travel{
public abstract void buyTickets(); //抽象方法
}
class Holiday extends Travel{
@Override
public void buyTickets() {
System.out.println("去携程买机票!");
}
}
4. 接口——interface
所谓
interface
,就是比抽象类还要抽象的纯抽象接口,因为它不能有实例字段,但是可以有静态字段。
当一个具体的class
去实现一个interface
时,需要使用implements
关键字。
default
方法的目的:当给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default
方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。(JDK>=1.8)
- Tips:
- 一个类只能
extends
一个class;但是可以implements
多个interface - 因为接口定义的所有方法默认都是
public abstract
的,所以这两个修饰符写不写效果都一样
- 一个类只能
public class Main {
public static void main(String[] args){
Holiday holiday = new Holiday();
holiday.buyTickets();
}
}
/*
接口 Travel
*/
interface Travel{
void buyTickets();
default String passport() { //default方法,可以不覆写
return null;
}
}
class Holiday implements Travel{
@Override
public void buyTickets() {
System.out.println("去携程买机票!");
}
}
5. 静态方法/字段——static
静态字段属于所有实例共享的字段,即:所有实例共享一个静态字段。它是属于class的。
代码中由于number
是静态字段,所以将p1.number
赋值为10,那么p2.number
也自动为10了。
public class Main {
public static void main(String[] args){
Person p1 = new Person("asher",23);
Person p2 = new Person("Chalice",2);
p1.number = 10;
System.out.println(p2.number); //10
}
}
class Person{
private String name;
private int age;
public static int number; //静态字段 number
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
- Tips:上面代码中不推荐用
实例变量.静态字段
p1.number
去访问静态字段。因为在Java程序中,实例对象并没有静态字段。在代码中,实例对象能访问静态字段只是因为编译器可以根据实例类型自动转换为类名.静态字段
来访问静态对象。推荐用类名来访问静态字段。可以把静态字段理解为描述class
本身的字段(非实例字段)。对于上面的代码,更好的写法是:
Person.number = 10;
System.out.println(Person.number); //10
接口的静态字段:interface
接口虽然不能定义实例字段,但是可以定义静态字段,并且静态字段必须为final
类型。实际上因为interface
的字段只能是public static final
类型,所以我们可以把这些修饰符都去掉:
public interface Person {
int MALE = 1; //等效于 public static final int MALE = 1;
int FEMALE = 2; //等效于 public static final int FEMALE = 2;
}