Java学习日记(四)继承、super、抽象类、接口

一、继承

1.概述

◆多个类中存在相同属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可

◆多个类可以成为子类,单独这个类称为父类或者超类

◆子类可以直接访问父类中的非私有的属性和行为

◆通过关键字extends让类与类之间产生继承关系

       class SubDemo extends Demo()

继承的出现提高了代码的复用性

继承的出现让类与类之间产生了关系,提供了多态的前提

 

2.特点

◆Java只支持单继承,不支持多继承

       ·一个类只能有一个父类,不可以有多个父类

       ·class SubDemo extends Demo{} //OK

       ·class SubDemo extends Demo1,Demo2…{}//error

◆Java支持多层继承(继承体系)

       ·class A{}

       ·class B extends A{}

       ·class C extends B{}

附注:因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。但是java保留这种机制。并用另一种体现形式来完成表示。多实现。

示例1:

class A{

       void demo1(){}

}

class B extends A{

       void demo2(){}

}

class C extends B{

       void demo3(){}

}

问:如何使用一个继承体系中的功能呢?

答:想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中共性功能,通过了解共性功能,就可以知道该体系的基本功能。

问:确认这个体系已经可以使用了,那么在具体调用的时候,为什么要创建最子类的对象?

答:1.因为有可能父类不能创建对象;2.创建子类对象可以使用更多的功能,包括基本的也包括特有的功能。

总而言之:查阅父类功能,创建子类对象使用功能。

◆定义继承需要注意:

       ·不要仅为了获取其他类中某个功能而失去继承

       ·类与类之间要有所属(“is a”)关系,xx1是xx2的一种

示例:

class Person{
       String name;
       int age;
}

class Student extends Person{      
       void study(){
              System.out.println("name:"+name+"---age:"+age+"...goodstudy");
       }
}

class Worker extends Person{
       void work(){
              System.out.println("name:"+name+"---age:"+age+"...goodwork");
       }
}

class ExtendsDemo{
       public static void main(String[] args){
              Student s=new Student2();
              s.name="zhangsan";
              s.age=14;
              s.study();
              Worker w=new Worker();
              w.name="lisi";
              w.age=30;
              w.work();
       }
}

运行结果:

name:zhangsan---age:14...good study

name:lisi---age:30...good work

 

3.super关键字

◆super和this的用法相同

◆this代表本类引用

◆super代表父类引用

◆当父类出现同名成员是,可以用super进行区分

◆子类要调用父类构造函数时,可以使用super语句

示例1:(this回顾)

class Fu {
       private int num = 4;
       public void setNum(int num){
              this.num=num;
       }
       public int getNum(){
              return this.num;
       }
}
class Zi extends Fu{
       int num = 5;
       void show(){
              System.out.println(num);
       }

}

class ExtendsDemo2{

       public static void main(String[] args) {
              Fu f=new Fu();
              System.out.println(f.getNum());
              Zi z = new Zi();
              z.show();
              System.out.println(z.num+"...."+z.num);
       }
}

运行结果:

4

5

5....5

示例2:(调用父类的成员)

class Person{
       String name;
       int age;
       public void eat(){
              System.out.println("eat...");
       }
       public void walk(){
              System.out.println("walk...");
       }
       public void sleep(){
              System.out.println("sleep...");
       }
}

class Student extends Person{

       public void dayLife(){
              super.eat();//调用父类的成员
              this.study();//调用本类的成员
              super.sleep();//调用父类的成员
       }
       public void study(){
              System.out.println("study...");  
       }
}

public class ExtendsDemo {
       publicstatic void main(String[] args) {
              Student stu=new Student();
              stu.dayLife();
       }
}

运行结果:

eat...

study...

sleep...

示例3:(调用父类的构造函数)

class Person{
       String name;
       int age;
       Person(String name,int age){
              this.name=name;
              this.age=age;
       }
       public void eat(){
              System.out.println("eat...");
       }    
}

class Student extends Person{
       //调用父类的构造函数
       Student(Stringname, int age) {
              super(name,age);
       }
       public String toString(){
              return "name:"+name+"----age:"+age;
       }
}

public class ExtendsDemo {
       public static void main(String[] args) {
              Student stu=new Student("zhangsan",18);
              System.out.println(stu.toString());
              stu.eat();
       }
}

运行结果:

name:zhangsan----age:18

eat...

补充:

子父类出现后,类成员的特点:

类中成员:变量、函数、构造函数。

 

4.函数覆盖

◆子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写

◆父类中的私有方法不可以被覆盖

◆在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取

◆覆盖注意事项

       ·覆盖时,子类方法权限一定要大于等于父类方法权限

       ·静态只能覆盖静态

◆覆盖的应用

       当子类需要覆盖父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容

示例:

class Fu {
       void show() {
              System.out.println("fushow");
       }
       void speak() {
              System.out.println("fu----vb");
       }
}
class Zi extends Fu {
       void speak() {
              System.out.println("zi----java");
       }
       void show() {
              System.out.println("zishow");
       }
}
public class ExtendsDemo {
       public static void main(String[] args) {
              Fuf=new Fu();
              f.speak();
              f.show();
              Ziz = new Zi();
              z.speak();
              z.show();
       }
}

运行结果:

fu----vb

fu show

zi----java

zi show

附注:

重载:只看同名函数的参数列表。

覆盖(重写):子父类方法要一模一样。

 

5.子类的实例化过程

◆子类中所有的构造函数默认都会访问父类中空参数的构造函数

◆因为子类每一个构造函数的第一行都有一条默认的隐式语句super()

◆子类会具备父类中的数据,所以要先明确父类是如何对子类这些数据初始化的

◆当父类中没有空参数的构造函数时,子类的构造函数必须手动通过super语句指定要访问父类的构造函数

子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

示例:

class Fu{
       int num;
       Fu(){
              num=60;
              System.out.println("furun");
       }
       Fu(int x){
              System.out.println("fu..."+x);
       }
}
class Zi extends Fu{
       Zi(){
              super(4);
              System.out.println("zirun");
       }
       Zi(intx){
              this();
              System.out.println("zi..."+x);
       }
}

public class ExtendsDemo {
       public static void main(String[] args) {
              Ziz = new Zi();
              System.out.println(z.num);
       }
}

运行结果:

fu...4

zi run

0

总结:

子父类中的构造函数:

在对子类对象进行初始化时,父类的构造函数也会运行,因为子类的构造函数默认第一行有一条隐式的语句 super()

super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();

问:为什么子类一定要访问父类中的构造函数?

答:因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问一下父类中的构造函数。

如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。

注意:super语句一定定义在子类构造函数的第一行。

 

6.final关键字

◆final可以修饰类、方法、变量

◆final修饰的类不可以被继承(为了避免被继承,被子类覆盖功能)

◆final修饰的方法不可以被覆盖

◆final修饰的变量是一个常量,只能赋值一次。既可以修饰成员变量,也可以修饰局部变量。当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过_连接。

◆内部类只能访问被final修饰的局部变量

示例1:(不能覆盖)

class FinalMethodTest{
       //定义成员变量时要指定默认值
       final int x = 3;
       //定义常量
       public static final double PI = 3.14;
       public final void test(){}
}

class Sub extends FinalMethodTest{
       //下面方法定义将出现编译错误,不能覆盖final方法
       public void test(){}

}

示例2:(能“覆盖”)

class PrivateFinalMethodTest{
       private final void test(){}
}

class Sub extends PrivateFinalMethodTest {
       //下面方法定义不会出现问题
       public void test(){}
}

从上面两个示例我们可以获知:对于一个private修饰的方法,只能在本类中访问,其子类无法访问,所以子类无法重写该方法——如果子类中定义一个与父类private修饰的方法相同的方法名、相同的形参列表、相同返回值类型的方法时,也不能重写,只是定义了新的方法而已。因此,即使使用final修饰一个private访问权限的方法时,依然可以在其子类中定义与该方法具有同名、同形参、同返回值类型的方法。

 

7.抽象类

7.1抽象类概述

       抽象定义:

              ·抽象就是从多个事物中将共性的,本质的内容抽取出来

              ·例如:狼和狗共性都是犬科,犬科就是抽象出来的概念

       抽象类:

              Java中可以定义没有方法的方法,该方法的具体实现子类完成,该方法成为抽象方

       法,包含抽象方法的类就是抽象类

       抽象方法的由来:

              ·多个对象都具有相同的功能,但是功能具体内容有所不同,那么在抽取过程中,      只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法成为    抽象方法

              ·例如:狼和狗都有吼叫的方法,可以吼叫内容是不一样的。所以抽象出来的犬科       虽然有吼叫功能,但是并不明确吼叫的细节

7.2抽象类特点

◆抽象类和抽象方法必须用abstract关键字来修饰

抽象方法只有方法声明,没有方法体,定义在抽象类中

       格式:修饰符 abstract 返回值类型 函数名(参数列表)

抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:

       ·抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬类是一个抽象的概念,真实存在的是狼和狗

       ·而且抽象类即使创建了对象,调用抽象方法也没有意义

◆抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类还是抽象类

附注:

抽象类和一般类没有太大的不同。该如何描述事物,就如何描述事物,只是该事物出现了一些看不懂的东西,也就是该事物的功能,需要明确出现,又无法定义主体,所以通过抽象方法来表示。

抽象类比一般类多个了抽象函数,就是在类中可以定义抽象方法。抽象类不可以实例化。

特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象

示例:

abstract class Student{
       abstract void study();
       void sleep(){
              System.out.println("sleep…");
       }
}

class ChongCiStudent extends Student{
       void study(){
              System.out.println("chongcistudy");
       }
}

class BaseStudent extends Student{
       void study(){
              System.out.println("basestudy");
       }
}

class AdvStudent extends Student{
       void study(){
              System.out.println("advstudy");
       }
}

class AbstractDemo {
       public static void main(String[] args) {
              //抽象类不可以实例化s
              //newStudent();
              newBaseStudent().study();
       }
}

运行结果:

base study

练习一:假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

代码实现:

abstract class Employee{
       private String name;
       private String id;
       private double pay;
       Employee(Stringname,String id,double pay){
              this.name= name;
              this.id= id;
              this.pay= pay;
       }    
       public abstract void work();

}

class Manager extends Employee{
       private int bonus;
       Manager(Stringname,String id,double pay,int bonus){
              super(name,id,pay);
              this.bonus= bonus;
       }
       publicvoid work(){
              System.out.println("managerwork");
       }

}

class Pro extends Employee{
       Pro(Stringname,String id,double pay){
              super(name,id,pay);
       }
       public void work(){
              System.out.println("prowork");
       }
}

练习二:获取一段程序运行的时间。

原理:获取程序开始和结束的时间并相减即可。(获取时间:System.currentTimeMillis();)

模版方法设计模式

在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去,由该类的子类去完成。

代码实现:

abstract class GetTime{
       public final void getTime(){
              long start = System.currentTimeMillis();
              runcode();
              long end = System.currentTimeMillis();
              System.out.println("毫秒:"+(end-start));
       }
       publicabstract void runcode();
}

class SubTime extends GetTime{
       public void runcode(){         
           for(int x=0; x<20; x++){
              System.out.print(x);
           }
       }
}

class TemplateDemo{
       public static void main(String[] args) {
          SubTime gt = new SubTime();
          gt.getTime();
       }
}

运行结果:

01234567891011121314151617181920毫秒:1

 

7.3抽象类相关问题

◆问:抽象类中是否有构造函数?

答:有,抽象类是一个父类,要给子类提供实例的初始化。

◆问:抽象关键字abstract不可以和哪些关键字共存?

答:final:被final修饰的类不能有子类,而被abstract修饰的类一定是一个父类。

       private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写,而抽象方法出现的就是需要被复写。

       static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了,可是抽象方法运行没意义。

◆问:抽象类中可不可以没有抽象方法?

答:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象

 

二、接口

初期理解,可以认为是一个特殊的抽象类;

当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。

格式:interface{}

接口中的成员修饰符是固定的。

       ·成员常量:public static final

       ·成员函数:public abstract

附注:接口中的成员都是public修饰的,接口是不可以创建对象的,因为有抽象方法

接口的出现将“多继承”通过另一种形式体现出来,即“多实现”

特点:

       ·接口是对外暴露的规则

       ·接口是程序的功能扩展

       ·接口可以用来多实现

       ·类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口

       ·接口与接口之间可以有继承关系

示例:

interface Inter {
       public static final int NUM = 3;
       public abstract void show();
}

interface InterA {
       public abstract void show();
}

class Demo {
       public void function() {}
}

class Test extends Demo implements Inter,InterA {
       public void show() {}
}

class InterfaceDemo {

       public static void main(String[] args) {
              Test t = new Test();
              System.out.println(t.NUM);
              System.out.println(Test.NUM);
              System.out.println(Inter.NUM);
       }
}

运行结果:

3

3

3

练习:数据库的操作

代码实现原理:

interface UserInfoDao{
       public void add(User user);
       public void delete(User user);
}

class UserInfoByJDBC implementsUserInofDao{
       public void add(User user){
              1.JDBC连接数据库;
              2.使用sql添加语句添加数据;
              3.关闭连接;
       }

       public void delete(User user){
              1.JDBC连接数据库;
              2.使用sql添加语句删除数据;
              3.关闭连接;
       }
}

class UserInfoByHibernate implementsUserInfoDao{
       public void add(User user){
              1.Hibernate连接数据库;
              2.使用sql添加语句添加数据;
              3.关闭连接;
       }

       public void delete(User user){
              1.Hibernate连接数据库;
              2.使用sql添加语句删除数据;
              3.关闭连接;
       }
}

class DBOperate{

       public static void main(String[] args) {
              UserInfoByJDBC uij = new UserInfoByJDBC();
              uij.add(user);
              uij.delete(user);
              UserInfoByHibernate uih = new UserInfoByHibernate();
              uih.add(user);
              uih.delete(user);
       }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值