继承
1、继承
良好的代码是指 结构性合理、适合于维护、可重用性高
下面定义两个类:人类、学生类
学生属于人类,因此学生是一个相对狭小的范畴
在Java程序中小要实现继承关系,需要依靠 extends 关键字来完成,
class 子类 extends 父类{}
很多情况下。会把子类成为派生类,把父类成为超类(superClass)
在继承中,具有一定的逻辑关系,这也对实例化定义有了一定的要求
按照正常的社会逻辑:没有你爹就一定没有你,对于继承程序的逻辑也是一样的,对象实例化的时候一定要默认实例化
public class JavaDemo{
public static void main(String [] args){
Student stuA = new Student() ;
stuA.setName("沈梦琳") ;
stuA.setAge(18) ;
stuA.setSchool("普林斯顿大学") ;
System.out.println("姓名:" + stuA.getName() +"、年龄:" + stuA.getAge()) ;
System.out.println("学校:" + stuA.getSchool()) ;
}
}
//父类 Person
class Person{
private String name ;
private int age ;
public Person(){}
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
}
//Student 类 继承 Person 类
class Student extends Person{
private String school ;
public Student(){}
public Student(String school){
this.school = school ;
}
public void setSchool(String school){
this.school = school ;
}
public String getSchool(){
return school ;
}
}
即使没有进行父类对象实例化,系统也会自动调用父类的构造方法(实例化父类)
这其中相当于子类的构造方法中隐含了一个super() 方法
super() 方法表示的是 父类的 构造方法,该语句只能放在子类的构造方法的 首行
super() 方法会调用无参构造,因此写与不写无所谓
如果父类中没有无参构造,那么就需要super() 方法调用有参构造
下面是无参构造
public class JavaDemo{
public static void main(String [] args){
Student stuA = new Student() ;
}
}
class Person{
public Person(){
super(); //这一步可以省略
System.out.println("【父类实例化对象】") ;
}
}
class Student extends Person{
public Student(){
System.out.println("【子类实例化对象】") ;
}
}
下面是有参构造
public class JavaDemo{
public static void main(String [] args){
Student stuA = new Student() ;
}
}
class Person{
private String name ;
private int age ;
//有参构造
public Person(String name , int age ){
this.name = name ;
this.age = age ;
System.out.println("姓名:"+ name + "年龄:" + age);
System.out.println("【父类实例化对象】");
}
public void setName(String name ){
this.name = name ;
}
public void setAge(int age ){
this.age = age ;
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
}
class Student extends Person{
public Student(){
super("沈梦琳",18); //调用父类的 有参构造
System.out.println("【子类实例化对象】") ;
}
}
继承的相关限制
Java中不允许多重继承,只允许多层继承
- 在实际生活中,一个人只能有一个父亲,那么在程序中也是这样的
- 继承的主要目的,是扩展已有类的功能,但是多重继承的目的是希望可以同时继承多个类的方法
而面对多继承的要求应该,将范围限定在同一类中,如果现在使用了多层继承,那么可以连续继承,而不是同时继承,但是多层继承,也有限度,逻辑上不能多次连续继承,逻辑上最多是三层,更多的话,会造成代码的混乱
私有操作属于隐式继承,非私有操作属于非隐式继承
public class JavaDemo{
public static void main(String [] args){
Student student = new Student("沈梦琳") ;
student.getInfo() ;
}
}
class Person{
private String name ;
public Person(){}
public void setName(String name){
this.name = name ;
}
public String getName(){
return name ;
}
}
class Student extends Person{
public Student(){}
//隐式继承
public Student(String name){//通过set方法来进行访问私有属性
setName(name);//通过set方法进行间接访问
}
public void getInfo(){
//System.out.println(name) ; //这一步并不能真的实现
System.out.println(getName()) ;//通过get方法来进行获取私有属性
}
}
在继承中,并没有像现实生活中,并没有体现子类减少父类的方法
2、final
在程序中,final 描述的是终接器的概念,在java中使用final关键字可以实现方法或者属性不被重写
即无法有子类,或者不能被重写
final修饰类时,该类不能有子类
final修饰方法时,该方法在子类中不能够重写
final修饰属性时,该属性不能在子类中被属性覆写
可以利用final来定义一些逻辑上不能更改的常量
比如说 0 表示关,1 表示开,就可以利用final来修饰
private final int on = 1 ;
private final int off = 0 ;
也可以通过final来定义全局常量
private static final int ON = 1 ;
private static final int OFF = 0 ;
一旦是使用了final来修饰一个属性的值,那么就表示该属性是一个常量,不会变化
3、子类重写
在继承后,子类会继承父类的全部定义,但是这里面也有可能出现不合适的方法,但是又需要保留父类中的方法或者属性,
这时候可以利用子类重写方法
当子类定义了父类方法名称相同,参数类型和个数完全相同的时候,就称为方法的重写
public class JavaDemo{
public static void main(String [] args){
Database database = new Database() ;
database.connect() ; //输出为:数据库连接
}
}
class Connect{
public void connect(){
System.out.println("连接") ;
}
}
class Database extends Connect{
public void connect(){ //重写父类方法
System.out.println("数据库连接") ;
}
}
在子类重写之后,需要调用父类的方法,需要使用super().方法 来调用父类方法
class Database extends Connect{
public void connect(){ //重写父类方法
super.connect() ; //调用父类的方法
System.out.println("数据库连接") ;
}
}
被重写的方法,没有比父类更为严谨的访问权限
public > default > private
在父类中定义了一个default 的方法,在子类中重写的时候只能使用default 或者 public;
在父类中定义了一个public 的方法,在子类中重写的时候只能使用public
public class JavaDemo{
public static void main(String [] args){
Database database = new Database() ;
database.connect() ;
}
}
class Connect{
void connect(){ //default
System.out.println("连接") ;
}
}
class Database extends Connect{
public void connect(){ //重写父类方法,此时的重写 只能是 default 或者public
super.connect() ;
System.out.println("数据库连接") ;
}
}
当父类的方法设置为private 那么 该方法 就属于 父类私有的,那么子类就无法重写
public class JavaDemo{
public static void main(String [] args){
Database database = new Database() ;
database.fun() ; // //输出的是父类的“连接”
}
}
class Connect{
private void connect(){ //当这里的private是public或者default的时候,输出的是子类的“数据库连接”
System.out.println("连接") ;
}
public void fun(){
this.connect() ;
}
}
class Database extends Connect{
public void connect(){ //重写父类方法
System.out.println("数据库连接") ;
}
}
属性覆盖
即在子类中重新定义属性,但是不重新定义属性的类型,只是单纯的改变赋值
但如果父类的属性采用的是private,那么子类就无法实现属性覆盖了,只是单纯的创造了一个新的属性
如果在父类属性使用了private后依然想访问父类的属性,可以使用getter()方法来获取
属性一旦封装,属性便无法覆盖,那么属性覆盖就没有意义了
public class JavaDemo{
public static void main(String [] args){
Database database = new Database() ;
database.fun() ; //输出为 子类覆写后的名字 沈梦琳
System.out.println(database.getAge()) ; //无法覆写,只能通过getter方法来获取数据
}
}
class Connect{
String name = "嘿嘿嘿"; //不封装属性
private int age = 18 ; //封装 属性
public Connect(){}
public Connect(String name , int age ){
this.name = name ;
this.age = age ;
}
public void setName(String name ){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
}
class Database extends Connect{
String name = "沈梦琳" ; //子类覆写父类的属性
public Database(){}
public void fun(){
System.out.println(name) ;
}
}