发表于: 2020-11-28 22:49:18
1 1298
今天完成的事情:
类,超类和子类
import java.util.Date;
/**
* 5.继承
* 5.1 类,父类和子类
* 1.继承就是子类可以使用父类的方法和变量,然后在这个基础上还可以添加新的方法和域
* 注意:子类无法删除继承的任何变量和方法。
*
* 2.覆盖,就是在子类中重写父类的方法。重写不能直接进行重写,需要用到super关键字,不然编译器无法识别使用子类的方法和父类的方法。
* 然后就会导致无限循环的调用自己,知道程序崩溃
* 注意:子类不能调用父类的私有变量,但是可以调用公共方法,也可以说是公共接口,这样就间接的访问了私有变量
*
* 3.super关键字和this的区别:
* this关键字是调用当前类的变量,和局部变量区别开来。也可以调用该类的其他构造器
* super关键字是调用父类的方法,也可以调用父类的构造器
* 总结:super关键字不是一个对象的引用,不能将super赋给另一个对象变量
*
* 4.多态:一个对象变量(如:Student s)可以指示多种实际类型的现象被称为多态,在运行时能够自动的选择调用哪个方法的现象称为动态绑定。
*
*
* 5.1.1 继承层次
* 1.Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。
*
*
* 5.1.2 多态
* 1.子类的每个对象都是父类的对象。例:每个大学生都是学生,但每个学生并不是大学生。
* 2.父类对象的任何地方都可以用子类对象置换,但是子类无法引用父类的对象。例子:pupil[0] = hong;
* 3.对象变量是多态的,一个父类变量可以引用Student类对象,也可以引用子类的对象。
* 4.pupil[0] = hong;这引用的是一个子类对象,但编译器将pupil[0]看成Student父类对象,所以pupil[0].setGPA(0.1)(这个是子类的方法);会报错
*
* 5.1.3 动态绑定
* 1.涉及到了编译器,重载解析,静态绑定,虚拟机,方法表,覆盖,方法的签名。名词很多。看了一遍,看得懂,也只是看的懂而已
* 2.编译器:将Java源文件(.java文件)编译成字节码文件(.class文件)
* 重载解析:编译器将查看调用方法时提供的参数类型。如果在所有名为f的方法中存在一个与提供参数类型完全匹配,就选择这个方法。
* 方法签名:方法的名字和参数的列表,例子:valueOf(char c) 和 valueOf(double d)
* 静态绑定:用private,static,final修饰方法时,编译器会自动调用这些方法
* 方法表:虚拟机会预先为每一个类创建一个方法表,在其中列出所有方法的签名和实际调用的方法。目的是为了增加搜索速度
*
*
* 5.1.4 阻止继承:final类和方法
* 1.目的:确保不会在子类中不会改变语义。
* 2.使用方法,在类名class前加上 final,这样做了子类就不能覆盖这个类当中所以方法了。
*
* 5.1.5 强制类型转换
* 1.目的,唯一原因:在暂时忽视对象的实际类型之后,使用对象的全部功能。
* 2.直接在转换的对象前加上(类名)。例子:UniversityStudent hong = (UniversityStudent) pupil[0]
* 3.子类转父类可以,父类转子类不行。
* 4.父类转子类之前,应该使用instanceof检查
* 5.只能在继承层次内进行转换。
* 6.一般情况,少用类型转换和instanceof运算符
*
*
*/
public class UniversityStudent extends Student {
private int SelfStudyTime;
private double GPA;
/**
* private String name;
* private double score;
* private Date StartLearnDay;
* @return
*/
//会无限制的调用,因为UniversityStudent也有一个getScore方法,就是正在实现的这个方法。为什么它会一直重复运行???
//覆盖父类的方法
public double getScore(){
//不能使用return score+GPA;因为score在父类中是private,只能使用公共方法getScore
System.out.println("======");
double baseScore = super.getScore();//super关键字指的是调用父类student中的getScore方法,这样就和子类的getScore方法区别开来
return GPA=baseScore/100;
}
public UniversityStudent(String name, double score, int year, int month, int day){
super(name,score,year,month,day);
GPA = 0;
}
public void setGPA(double g){
GPA = g;
}
public UniversityStudent() {
}
public static void main(String[] args) {
UniversityStudent hong = new UniversityStudent();
hong.getScore();
}
}
父类
import java.util.Date;
import java.util.GregorianCalendar;
public class Student {
private String name;
private double score;
private Date StartLearnDay;
public Student() {
}
public Student(String name, double score, int year, int month, int day){
this.name = name;
this.score = score;
//公历用0表示一月,所以month-1
GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);
StartLearnDay = calendar.getTime();//获取公历的时间
}
public boolean equals(Student other){
return name.equals(other.name);
}
//因为对属性设置private,所以需要通过getXXX来获取属性,这就是get的目的
public String getName(){
return name;
}
public double getScore(){
return score;
}
public Date getStartLearnDay(){
return StartLearnDay;
}
public void raiseScore(double byPercent){
double raise = score * byPercent/100;
score +=raise;
}
}
测试类
public class UniversityStudentTest {
public static void main(String[] args) {
//将一个子类的对象赋给超类变量
Student S;
S = new Student();
S = new UniversityStudent();
UniversityStudent hong = new UniversityStudent("小红",465,2015,9,20);
hong.setGPA(1.0);
Student[] pupil = new Student[3];
pupil[0] = hong;
pupil[1] = new Student("小光", 516,2020,9,8);
pupil[2] = new Student("小黄", 472,2020,9,8);
//强制类型转换
// UniversityStudent ming = (UniversityStudent) pupil[1];//报错:类强制转换异常,父类不能转换成子类
//能转就转,不能转就跳过。
if (pupil[1] instanceof UniversityStudent)
{
UniversityStudent ming = (UniversityStudent) pupil[1];
}
// hong.setGPA(0.1);
// pupil[0].setGPA(0.1);//无法解析“Student”中的方法“setGPA”
//注意这里使用s.getScore()方法时,能自动分别是调用子类还是调用父类的方法,根据s引用的对象不同
for (Student s : pupil)
System.out.println("name=" + s.getName() + ",score" + s.getScore() +
",StartLearnDay" + s.getStartLearnDay());
}
}
结果:
抽象类
抽象父类
public abstract class Person {
//描述
public abstract String getDescription();
private String name;
public Person(String n){
name = n;
}
public String getName(){
return name;
}
}
子类A
import java.util.Date;
import java.util.GregorianCalendar;
public class Employee extends Person {
private double salary;
private Date hireDay;
public Employee(String n, double s, int year, int month , int day){
super(n);
salary = s;
GregorianCalendar calendar = new GregorianCalendar(year , month-1, day);
hireDay = calendar.getTime();
}
public double getSalary() {
return salary;
}
public Date getHireDay(){
return hireDay;
}
public String getDescription(){
return String.format("一个雇员的薪水为 $%.2f", salary);
}
public void raiseSalary(double byPercent){
double raise = salary * byPercent /100;
salary += raise;
}
}
子类B
public class Student extends Person {
private String major;
/**
* @param n 是学生的名字
* @param m 是学生的专业
*/
public Student(String n,String m){
//将n传递给父类构造函数
super(n);
major = m;
}
//“Student”类必须声明为abstract或在“Person”中实现抽象方法“getDescription()”
public String getDescription(){
return "一个学生的专业是"+ major;
}
}
测试类
/**
* 5.1.6 抽象类
* 为什么要定义抽象类?
* 为了子类能够更清晰的描述程序,特别是一个类有多个子类的情况下。父类越抽象,子类就能描述的更多
*
* 父类定义为抽象类之后,有什么后果?
* 父类无法实例化,但可以创建具体的子类对象。例子:people[1] = new Student("小黑", "机械及其自动化");
*
* 为什么抽象类可以创建数组?
* 看网上的介绍是:因为数组本身就是一个对象,创建数组时,是创建一个数组对象,不是抽象数组。
*
* 1.子类中必须实现父类的抽象方法,或者将子类也定义为抽象方法。
* 2.p.getDescription(),这个由于不能创建父类person的对象,所以p永远不会引用person的对象
* 3.父类中的抽象方法不能省略。
*
* 5.1.7 受保护访问
* 1.想让父类中的方法和变量被子类访问,需要将方法或者域声明为protected.
* 2.这种方法最好的实例是第六章的Object类中的clone方法。
*/
public class PersonTest {
public static void main(String[] args) {
Person[] people = new Person[2];
// People ming = new Person();//People是抽象的,无法实例化
people[0] = new Employee("小明", 8000, 2020 , 11, 1);
people[1] = new Student("小黑", "机械及其自动化");
for (Person p : people)
System.out.println(p.getName() + "," + p.getDescription());
}
}
结果:
明天计划的事情:
Object类,泛型数组,接口
遇到的问题:
还是要在11点,15点,晚上8点写一下总结,全部拖到晚上写,脑子有点运行不过来
收获:
目前:Java基础第五章-类和超类,子类的学习完成
预计完成时间:11.29
评论