一、继承的基本概念
1.格式:
class 父类{}
class 子类 extends 父类{}
2.实现:
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
3.注意:
1)Java中一个子类只能有一个父类。
2)子类可以访问父类中的非私有方法,但不能直接调用父类中的私有成员(可通过getter/setter访问)。
二、继承的进一步研究
1.子类对象的实例化
子类对象在实例化之前,必须先调用父类中的构造方法(super()),之后再调用子类自己的构造方法。(先有爸爸才有孩子)
public class Test {
public static void main(String[] args) {
Student a = new Student();
a.setName("xxt");
a.setAge(22);
a.setSchool("dufe");
System.out.println(a.toString());
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
System.out.println("父类中的构造方法。");
}
}
class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public Student() {
//super();隐含这行,调用父类的无参构造方法。
System.out.println("子类中的构造方法。");
}
@Override
public String toString() {
return "Student [school=" + school + ", getName()=" + getName() + ", getAge()=" + getAge() + "]";
}
}
2.方法覆写:
子类定义了与父类中同名的方法,但是,子类的权限不能比父类严格。
1)覆写方法的调用:默认调用子类,但是想调用父类的话,用super.方法名()
public class Test {
public static void main(String[] args) {
Student a = new Student();
a.print();
}
}
class Person{
void print() {
System.out.println("父类的方法");
}
}
class Student extends Person{
public void print() {
super.print();//调用父类中的print()方法
System.out.println("子类的方法");
}
}
2)属性的覆盖:
与方法覆写类似,还存在一种叫做属性的覆盖。
子类父类出现相同属性时,访问时按照“就近访问原则”
public class Test {
public static void main(String[] args) {
new Student().fun();
}
}
class Person{
private void print() {
System.out.println("父类的方法");
}
public void fun() {
this.print();
}
}
class Student extends Person{
void print() {
System.out.println("子类的方法");
}
}
//程序运行结果:父类的方法
public class Test {
public static void main(String[] args) {
new Student().print();
}
}
class Person{
public String info = "HHHH";
}
class Student extends Person{
public String info = "AAAA";
public void print() {
System.out.println("父类中的属性:"+ super.info);
System.out.println("子类中的属性:"+ this.info);
System.out.println("就近的属性:"+ info);
}
}
//程序运行结果:
//父类中的属性:HHHH
//子类中的属性:AAAA
//就近的属性:AAAA
3)方法重写与重载对比:
3.super关键字:
1)作用:从子类中调用父类的构造方法,普通方法,属性
2)注意事项:super调用父类中制定的构造方法时,必须放在子类构造方法的首行
public class Test {
public static void main(String[] args) {
Student Monica = new Student("xxt",22,"DUFE");
System.out.println(Monica.getInfo());
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name,int age) {
this.setName(name);
this.setAge(age);
}
public String getInfo() {
return "姓名:"+this.getName()+";年龄:"+this.getAge();
}
}
class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public Student(String name,int age,String school) {
super(name,age);//看这里看这里
this.setSchool(school);
}
public String getInfo() {
return super.getInfo()+";学校:"+this.getSchool();//还有这里这里
}
}
3)super与this对比:
注意:无论子类怎么折腾,都必须先调用父类的构造方法。
因为this和super调用构造时都必须放首行,因此不可共同使用。
三、final关键字:
“完结器”——声明的类,不能有子类;声明的属性,不能被修改(即为常量);声明的方法,不能被重写。
final生命的常量,要求全部字母都大写。如:final String INFO= "xxx";
四、抽象类
1.作用:类的模板,专门当作父类,按照它的格式创建新的派生类。对象不能由抽象类直接创建,可由派生类创建。
2.使用规则:
1)抽象类和抽象方法由abstract关键字声明
2)包含抽象方法的类必须事抽象类
3)抽象方法不需要实现,只需要声明
4)抽象方法不能用private修饰
5)抽象类必须被子继承,子类(如果不是抽象类)必须覆写抽象类中的所有抽象方法。
3.示例:略。实际上抽象类就是比普通类多定义了抽象方法,不可以直接实例化对象,其他的和普通类并无区别。
五、接口
由全局常量+公共的抽象方法组成,可以理解为一种特殊的类。
1.接口定义格式:
interface 接口名称{
全局常量;
公共抽象方法;
}
注意:接口中的方法都是public的,即使不写public关键字,默认也是public的。
2.接口示例:
interface Inter1{
public static final String FLAG = "CHINA";//全局常量
public abstract void print(); //公共抽象方法
public abstract String getInfo();//公共抽象方法
}
//简写如下:
interface Inter2{
String FLAG = "CHINA";
void print();
String getInfo();
}
注意:由于接口定义中已经知名,接口中的属性都为全局常量,方法都为公共抽象的,因此接口可由Inter1简写Inter2的形式。
3.接口的实现:
1)实现格式:
class 实现类名称 implements 接口A,接口B,...{
...
}
由此可见,接口可以摆脱单继承的缺陷。
2)示例:
interface Inter1{
String AUTHOR = "李兴华";
void print();
String getInfo();
}
interface Inter2{
public void say();
}
class X implements Inter1,Inter2{
@Override
public void print() {
// TODO Auto-generated method stub
System.out.println("Hello,world!");
}
@Override
public String getInfo() {
// TODO Auto-generated method stub
return "hello";
}
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("作者:"+ AUTHOR);
}
}
public class Test {
public static void main(String args[]) {
X xman = new X();
xman.print();
xman.say();
xman.getInfo();
}
}
4.实现接口并继承抽象类:
class X extends A implements B { }
public class Test {
public static void main(String args[]) {
X xman = new X();
xman.print();
xman.say();
xman.getInfo();
}
}
interface A{
String AUTHOR = "李兴华";
void print();
String getInfo();
}
abstract class B{
public abstract void say();
}
class X extends B implements A{
@Override
public void print() {
System.out.println("Hello,world!");
}
@Override
public String getInfo() {
return "hello";
}
@Override
public void say() {
System.out.println("作者:"+ AUTHOR);
}
}
注意:接口是可以多继承的,抽象类不行。
六、对象的多态性
Java中面向对象的特征主要两点:1)方法的重写与重载。2)对象的多态性。
1.分类:
对象的多态性分两类:1)对象向上转型: 父类 父类对象 = 子类实例
2)对象向下转型: 子类 子类对象 = (子类)父类实例
2.示例:
注意:1)向上转型后的对象,所调用的方法一定是被子类覆写过的。不可调用子类中定义但父类中未定义的方法。
2)向下转型的要求:必须先对象向上转型,然后才可以向下转,否则出现对象转换异常。
public class Test {
public static void main(String args[]) {
A a = new B();//向上转型,a可以调用:覆写后的fun1,fun2
B b = (B)a;//向下转型,b可以调用:覆写过的fun1,fun2,fun3
a.fun1();//输出:子类中的fun1
a.fun2();//输出:子类中的fun1
b.fun1();//输出:子类中的fun1
b.fun2();//输出:子类中的fun1
b.fun3();//输出:子类中的fun3
}
}
class A{
public void fun1() {
System.out.println("父类中的fun1");
}
public void fun2() {
this.fun1();
}
}
class B extends A{
public void fun1() {
System.out.println("子类中的fun1");
}
public void fun3() {
System.out.println("子类中的fun3");
}
}
七、instanceOf关键字
1.作用:判断对象是哪个类的实例
2.格式:对象 instanceof 类 → 返回Boolean
3.示例:
public class Test {
public static void main(String args[]) {
A a1 = new B();
System.out.println(" A a1 = new B():" + (a1 instanceof A));//true
System.out.println(" A a1 = new B():" + (a1 instanceof B));//true
A a2 = new A();
System.out.println(" A a2 = new A():" + (a2 instanceof A));//true
System.out.println(" A a2 = new A():" + (a2 instanceof B));//false
}
}
class A{
public void fun1() {
System.out.println("父类中的fun1");
}
public void fun2() {
this.fun1();
}
}
class B extends A{
public void fun1() {
System.out.println("子类中的fun1");
}
public void fun3() {
System.out.println("子类中的fun3");
}
}
由此可见,向上转型都true,向下转型就不行了。
因此,instanceof 的一个功能就是:在做向下转型之前进行判断,这样可以避免类型转换异常。
4.向下转型前的判断:
public class Test {
public static void main(String args[]) {
fun(new B());
fun(new C());
}
public static void fun(A a) {//判断是哪个子类,然后调用该子类自己的方法。
a.fun1();
if(a instanceof B) {
B b = (B)a;
b.fun3();
}
if(a instanceof C) {
C c = (C)a;
c.fun4();
}
}
}
class A{
public void fun1() {
System.out.println("A中的fun1");
}
public void fun2() {
this.fun1();
}
}
class B extends A{
public void fun1() {
System.out.println("B中的fun1");
}
public void fun3() {
System.out.println("B中的fun3");
}
}
class C extends A{
public void fun1() {
System.out.println("C中的fun1");
}
public void fun4() {
System.out.println("C中的fun3");
}
}
八、抽象类和接口的应用
1.抽象类的实际应用——模板设计
抽象类相当于定义了一个模板,在主方法中调用它的普通方法(该普通方法调用了自身的抽象方法),而子类只需要实现其抽象方法,就可以取得一个具体的信息。
示例:
public class Test {
public static void main(String args[]) {
Person p1 = new Student("张三",20,90.0f);
Person p2 = new Worker("李四",30,6000.0f);
p1.say();
p2.say();
}
}
abstract class Person{
//属性
private String name;
private int age;
//构造器
public Person(String name,int age) {
this.name = name;
this.age = age;
}
//getter
public String getName() {
return name;
}
public int getAge() {
return age;
}
//抽象方法
abstract String getContent();
//调用抽象方法的普通方法
public void say() {
System.out.println(this.getContent());
}
}
class Student extends Person{
//属性
private float score;
//构造器
public Student(String name, int age,float score) {
super(name, age);
this.score = score;
}
//getter
public float getScore() {
return score;
}
//重写抽象方法
@Override
String getContent() {
return "学生信息-->姓名:"+this.getName()+",年龄:"
+this.getAge()+",成绩:"+this.getScore();
}
}
class Worker extends Person{
//属性
private float salary;
//构造器
public Worker(String name, int age,float salary) {
super(name, age);
this.salary = salary;
}
//getter
public float getSalary() {
return salary;
}
//重写抽象方法
@Override
String getContent() {
return "工人信息-->姓名:"+this.getName()+",年龄:"
+this.getAge()+",薪资:"+this.getSalary();
}
}
2.接口的实际应用——制定标准
如下例,接口就是一个标准,只要符合这个标准,电脑就可以插入,不管你插入的是U盘还是打印机还是其它。
示例:
public class Test {
public static void main(String args[]) {
Flash f = new Flash();
Computer.plugin(f);//插入U盘
Print p = new Print();
Computer.plugin(p);//插入打印机
}
}
//USB接口
interface USB{
public void start();
public void stop();
}
//U盘实现了USB接口
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开始工作。");
}
@Override
public void stop() {
System.out.println("U盘停止工作。");
}
}
//打印机实现了USB接口
class Print implements USB{
@Override
public void start() {
System.out.println("打印机开始工作。");
}
@Override
public void stop() {
System.out.println("打印机停止工作。");
}
}
//电脑可以插入USB设备
class Computer{
public static void plugin(USB usb) {
usb.start();
System.out.println("===USB设备工作中===");
usb.stop();
}
}
九、内部类的扩展
一句话,抽象类中可以定义多个内部抽象类和接口;接口中也可以定义多个内部抽象类和接口。
十、抽象类VS接口
十一、实例分析:宠物商店
设计一个宠物商店,里面有多种宠物(暂定猫、狗),每只宠物有名称、颜色、年龄三种属性。在商店中,只要满足此宠物标准的都可以放入宠物店内,且提供根据宠物名称进行模糊查询,查询结果返回宠物的全部属性信息。
分析:
1.”宠物“是个标准 → interface。
2.“猫、狗” → 实体类两个,且都有名称、颜色、年龄三种属性,那么就得有相应的构造方法和getter方法。因此宠物interface中就得有getter的抽象方法。
3.”宠物商店“是一个存放宠物的数组。里面得包括 添加一只宠物的方法、按名称模糊查询宠物信息的方法(该方法返回值也是一个宠物类型的数组)。
4.其他:interface中的抽象方法,用到谁写谁,估计只能用到getName()。
输出查询结果信息时,估计会需要重写toString()。
确定数组长度时会比较烦,注意一下。
实现:
代码已实现,懒得贴了。