面向对象基础篇
封装、继承和多态
......接上篇
类的继承
面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。
在定义不同类的时候存在一些相同属性,可将这些共同属性抽象成一个父类,在定义其他子类时可以继承自该父类,减少代码的重复定义,子类可以使用父类中非私有的成员。
首先定义一个父类,
接着可以创建各种子类,继承一个类使用extends关键字:
public class Student extends Person{
}
类的继承可以不断向下,但是同时只能继承一个类。
标记为final的类不允许被继承:
public final class Person { //class前面添加final关键字表示这个类已经是最终形态,不能继承
}
当一个类继承另一个类时,属性会被继承,可以直接访问父类中定义的属性,除非父类中将属性的访问权限修改为private,那么子类将无法访问(但依然是继承了这个属性的):
public class Student extends Person{
public void study(){
System.out.println("我是学生,我叫"+name); //可直接访问父类中name属性
}
}
父类中定义的方法也会被子类继承,我们创建一个子类对象时可以直接使用这个方法:
public class Main {
public static void main(String[] args) {
Student student=new Student();
student.study(); //子类自己的独特技能
student.hello(); //继承了父类的全部技能
}
}
子类构造方法:
如果父类存在一个有参构造方法,子类必须在构造方法中调用。
子类在构造时,不仅要初始化子类的属性,还需要初始化父类的属性(无参的情况下省略了):
父类:
public class Person {
protected String name;
protected int age;
protected String sex;
protected Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
则子类:
public class Student extends Person{
protected Student(String name, int age, String sex) {
super(name, age, sex);
}
}
super()调用必须是构造函数主体中的第一条语句,在调用父类构造方法之前,不允许执行任何代码,只能在之后执行。
向上转型和向下转型:
我们在使用子类时,可以将其当作父类来使用:
public static void main(String[] args) {
Person person=new Student("小明",18,"男");//使用父类类型的变量,去引用一个子类对象(向上转型
person.hello(); //父类对象的引用相当于当做父类来使用,只能访问父类对象的内容
}
我们可以使用强制类型转换,将一个被当做父类使用的对象,转换回子类:
public static void main(String[] args) {
Person person=new Student("小明",18,"男");
Student student=(Student) person;//使用强制类型转换(向下转型)
student.study();
}
- 这种方法只适用于本身就是对应的子类
判断某个变量所引用的对象是什么类:
public static void main(String[] args) {
Person person=new Student("小明",18,"男");
if(person instanceof Student){
System.out.println("对象是Student类型的");
}
if(person instanceof Person){
System.out.println("对象是Person类型的");
}
}
如果变量所引用的对象是对应类型或对应类型的子类,那么instanceof都会返回true,否则false。
子类和父类成员变量同名:
子类可以定义和父类同名的属性,当我们在子类中直接使用时 作用于子类中定义的属性,
在子类存在同名变量的情况下,用super关键字来表示父类:
public void work(){
System.out.println("我是"+super.name);
}
顶层Object类
实际上所有类都默认继承自Object类,除非手动指定继承的类型,但是依然改变不了最顶层的父类是Object类。所有类都包含Object类中的方法。
标记为native的方法是本地方法。
对象比较equals方法:
//判断当前对象和给定对象是否相等,默认实现是直接用等号判断,也就是直接判断是否为同一个对象
public boolean equals (Object obj){
return (this ==obj);
}
public static void main(String[] args) {
Worker w1=new Worker("小明",18,"男");
Worker w2=w1;
System.out.println(w1.equals(w2));
}
获取对象信息:
//将当前对象转换为String的形式,默认情况下格式为 完整类名@十六进制哈希值
public String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
public static void main(String[] args) {
Worker w1=new Worker("小明",18,"男");
System.out.println(w1.toString());
}
方法的重写
重写:也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写和重载的区别:
区别 | 重写 | 重载 |
参数列表 | 一定不能修改 | 必须修改 |
返回类型 | 一定不能修改(除非可以构成父子类关系) | 可以修改 |
访问限定符 | 一定不能做更严格的限制(可以降低限制) | 可以修改 |
重写Object类中提供的equals方法:
public class Person {
String name;
int age;
String sex;
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override //重写方法可添加注解,默认情况下可以省略
public boolean equals(Object obj){ //重写方法要求与父类的定义完全一致
if(obj == null) return false; //如果传入的对象为null,肯定不相等
if(obj instanceof Person){ //只有是当前类型的对象,才能进行比较
Person person=(Person) obj; //先转换为当前类型
return this.name.equals(person.name)&& //字符串内容的比较必须使用equals方法
this.age==person.age && //基本类型直接==
this.sex.equals(person.sex);
}
return false;
}
}
public class Main {
public static void main(String[] args) {
Person p1=new Person("小明",18,"男");
Person p2=new Person("小明",18,"男");
System.out.println(p1.equals(p2));
}
}
//
结果为true
其他父类方法的重写:
基于这种方法可以重写的特性,对于一个类行为的定义,不同的子类可以出现不同的行为:
//父类Person中:
public void test(){
System.out.println("我是原本的实现");
}
//子类Student中:
public void test(){
System.out.println("我是学生");
}
//Main:
public class Main {
public static void main(String[] args) {
Person p1=new Student("小明",18,"男");
p1.test(); //依照实际对象Student,而不是引用对象Person
}
}
//输出结果:
我是学生
final最终形态:
如果我们不希望子类重写某个方法,我们可以在方法前添加final关键字,表示这个方法已经是最终形态:
public final void test(){
}
super:
重写父类方法时,若要调用父类原本的实现,同样可以使用super关键字:
//父类中
public void test(){
System.out.println("我是原本的实现");
}
public void test(){
super.test();
System.out.println("我是学生");
}
结果:
子类在重写父类时,不能降低父类方法中的可见性。可以在子类中提升权限。
若父类中方法test()是private,子类中可以存在public void test(){ },但并不是父类方法的重写。