JAVA学习---从头开始WEEK03

第三周

回顾
private关键字的特点:
被private修饰的变量/方法只能在本类中访问,外界类不能直接访问
2)private修饰的成员变量以及成员方法不能直接访问,但是可以通过公共的访问间接访问.
3)private权限修饰符的范围最小,只能在本类中访问

封装(接WEEK02)

package com.qf.private_05;

/**
 * 描述学生事物,
 *      学生事物有两个属性,姓名和年龄,性别
 *      定义成员show(),来展示学生信息
 *
 *      学生的行为: 学习JavaSE , 会敲代码
 *
 *      使用面向对象的方式,加入封装思想来测试学生事物
 *
 *    分析:
 *          学生事物----- 定义学生类
 *         1)分析属性
 *         姓名,                 String name;
 *          年龄,                 int age ;
 *          性别                  String sex ;
 *
 *                      类中成员变量(属性),全部私有化加入private
 *          2)分析事物行为:
 *          对外提供一个方法,公共的(public)访问方法(setXXX()/getXXX())
 *
 *              成员show(),来展示学生信息            public void show(){输出name,age,sex}
 *              学习JavaSE , 会敲代码               public void studyJavaSe()
 *                                               public void codding() 敲代码
 *
 */
public class StudentTest {
    public static void main(String[] args) {
        //描述具体的学生---创建学生对象 :类名 对象名 = new 类名();
       Student s = new Student() ;

       //对象名.成员变量 = 赋值;   //赋值这些值 肯定来数据库
        //s.name = "高圆圆" ;   //被private修饰的成员变量:只能在本类中访问,外界不能访问
       // s.age = 20 ;
       // s.sex = "女" ;

        //使用对象名.成员方法名() ;
        //给学生的信息赋值---调用setXXX()
        s.setName("高圆圆") ;
        s.setAge(43) ;
        s.setSex("女") ;

        System.out.println("学生的姓名是:"+s.getName()+",年龄是"+s.getAge()+",性别是:"+s.getSex());

        //调用这个学生的一些其他行为
        s.studyJavaSE();
        s.codding();
    }
}

基本类型作为形式参数和引用类型(数组,类,接口)作为形式参数的特点? (重点)

  • 基本类型作为形式参数:形参的改变不会实际参数;
  • 局部变量:生命周期:随着方法调用而存在,随着方法调用结束而结束;
    *String作为形式参数(引用类型),和基本类型作为形式参数是一样,形式参数的改变不会影响实际参数;
  • 引用作为形式参数:形式参数的改变直接影响直接实际参数,除String类

面试题:局部变量和成员变量的区别?

  •      1)书写位置不同:
           成员变量:类中,方法外!
           局部变量:方法定义中,或者方法声明上
         2)内置中的位置不同
            成员变量:堆内存中,和对象有关系
            局部变量:栈内存中,和方法有关系
    
       3)生命周期不同:
            成员变量:随着对象的创建而存在,
                            随着对象的创建完毕等待jvm的垃圾回收器空闲 时候回收而消失
            局部变量:随着方法的调用而存在,
                            随着方法调用结束而消失;
       4)初始化值不同:
                成员变量:是可以不初始化的,需要通过对象名来赋值,存在默认初始化;
                局部变量:必须在使用之前初始化,否则报错;
                什么时候把一个定义为成员变量的时机?
                    如果一个类能够描述这个事物的属性,必须为定义成员变量;
                    否则,都定义为局部变量;
    

局部变量和成员变量的区别

: *1)方法的形式参数如果是基本类型,调用该方法的时候,实际参数需要传递对应数据值即可

  • 2)方法的形式参数是引用类型:数组,类,接口,实际参数在进行传递需要传递当前数组对象 /类的对象/接口的对象
  • new :创建实例(堆内存开辟空间:空间地址值)

this关键字

this用来定义本类中的变量
this:代表当前类对象的地址值引用 Student s = new Student() ; s---->空间地址值的引用;
this的出现:
为了防止局部变量隐藏了成员变量,
构造方法:
public Phne(String brand ,int price){
this.brand = brand ;
thi.price = price ;
}
setxxx()
public void setBrand(String brand){
this.brand = brand ;
}
this的用法:
this.变量名; 变量名:访问本类的成员变量名
this.方法名() ; 访问的本类的成员方法
this()----- 访问本类无参构造方法…
this(xxx) 访问本类的有参构造方法…
this的图解

一个类成员的组成以及一个类的标准写法
一个类的组成
1)成员变量
2)构造方法
3)成员方法:
一个类的标准类的写法:
1)成员变量私有化
2)无参永远给出的,有参构造根据题意要求(没有明确,全部提供)
3)成员方法,根据题意要求(没有明确是否带参,是否有返回值,直接输出语句)

构造方法:

一个类的成员方法:

  •  类的成员变量:描述这个类有哪些属性
    
  •  类的成员方法:setXXX()/getXXX():赋值和获取值的成员方法以及事物的一些其他行为
    
  •  类的构造方法
    
  • 什么是类的构造方法----->是一个方法,比较特殊

  • 1)这个方法,方法名和类名相同
    2)这个方法,连void都没有
    3)构造方法是可以重载的;
    无参构造方法
    有参构造方法

  • 构造方法的目的:就是为了类的成员相关的数据进行初始化的;
    系统默认初始化
    显示初始化;

  • 注意事项:
    当一个类中没有任何构造方法(无参/有参),系统会默认提供无参构造方法;
    但是当如果提供有参构造方法,系统就不会在提供无参构造方法,无参构造就会报错;
    以后,写一个类的时候,为了防止无参构造无法访问,永远出无参构造方法;

  •       一个标准类的写法:
                成员变量私有化
                提供对外的公共访问方法,setXXX()/getXXX()
                提供无参构造/ 有参构造方法 (根据需求进行判断)
    

匿名对象

Java中有一个概念:匿名对象: 毋庸置疑,没有名字对象;
之前: 类名 对象名 = new 类名() ; 对象名
Student s = new Student() ; 里面的对象名是s
对象名.访问成员方法();

  •  匿名对象:
         ***格式:new 类名() ;***
           ***匿名对象调用方法
                  new  类名().成员方法名() ;***
    
  • 好处:    节省内存空间,new 类名() ;
     	     匿名对象可以作为参数传递
             创建完毕之后,没有栈内存指向,所以使用完毕,立即被GC(垃圾回收器回收)
              一般情况:匿名对象使用一次即可,这样不需要过多的去开辟堆内存空间,直接被回收;
    
package com.qf.noname;
class Student{
    public void study(){
        System.out.println("Good Good Study,Day Day Up!");
    }
}
//定义StudentDemo类
class StudentDemo{
    public void method(Student s){//形式参数是一个Student类型,引用类型
        s.study();//调用该方法,应该使用实际参数对象名在访问
    }
}
//测试类
public class NoNameDemo {
    public static void main(String[] args) {
            //要访问StudentDemo类中method方法
        //创建StudentDemo类对象|
        StudentDemo sd = new StudentDemo() ;
        //创建学生对象
        Student s = new Student() ;
        sd.method(s); //方法里面:形式参数 创建学生了学生对象
        System.out.println("--------------------");
        //使用匿名对象new  类名()
        //new  类名().成员方法名() ; //调用自己方法
        sd.method(new Student());
        System.out.println("--------------------");
        //再次优化:
        //链式编程(自己去玩,开发中很少)
        new StudentDemo().method(new Student());
    }
}

static关键字

static本身的含义:共享,共用,可以多个对象去共用;
被static修饰的成员变量或者成员方法---->随着类的加载而加载,优先于对象存在
被static访问方式的变量/方法—>静态变量/静态方法:
类名.变量名;
类名.方法名() ;
static使用场景:
一般就工具类(自定义的)或者jdk提供类:java.util.Arrays数组工具类
java.lang.Math:数学运算的工具类
java.util.Collections:针对集合工具类
他们的方法都是提供—static修饰的 (查看jdk的api文档)
一般说的成员的东西:都行需要对象来访问的
类名 对象名 = new 类名() ;
成员变量----非静态的
成员方法----非静态的

static关键字的特点:

  •  1)被静态修饰的随着类的加载而加载,优先于对象存在;
    2)不能和this共存;
    3)本身含义就是共享,共用;可以多个对象共享共用;
        这也是告诉我们,为什么将某个属性定义static
               举例: 饮水机的水----共享,共用
                    自己水杯中的水---不行的
    
    4)被静态修饰的成员变量或者成员方法(静态变量/静态方法) (掌握)
       访问的方式:
           可以使用对象名来访问但是,对于系统来说(jvm)静态的东西:变量/方法
                    都是类名直接访问;
                    类名.变量名;
                    类名.方法名()
    
  •                  上次用的java.lang.Math
                                public static double random()
                                Math.random() ;
    
  •  静态的使用场景适用于范围:(记忆的)
                简单记忆:静态只能访问静态;
                        静态方法中只能访问静态变量
                        静态方法只能调用静态方法;
                        非静态方法皆可以访问静态的东西也可以访问非静态的东西;
    
package com.qf.static_07;

public class PersonTest {

    public static void main(String[] args) {
        //测试
        //描述 古代四大美女
        //创建第一个人
        描述古代四大美女,每一个人的国籍都是 "中国",从内存角度考虑,堆内存中开辟空间,为类的属性进行系统默认初始化,然后地址值产生,进行显示初始化,这个四个人的国籍都是一样的,比较耗费内存空间,这个程序看起来很臃肿(冗余度大)
 解决问题:
 *   Java提供了一个关键字 static :本身含义:共有,共享的意思
 *  在county上面加入一个关键字static  ---->随着类的加载而加载(优先于对象的创建之前完成)
        Person p1 = new Person("貂蝉",25,"中国") ;
        p1.show();
        //Person p2 = new Person("王昭君",18,"中国") ;
        Person p2 = new Person("王昭君",18);
        p2.show();
        //Person p3 = new Person("西施",22,"中国") ;
        Person p3 = new Person("西施",22);
        p3.show();
        //Person p4 = new Person("杨玉环",26,"中国") ;
        Person p4 = new Person("杨玉环",26);
        p4.show();
    }
}

优化后如下:

package com.qf.static_07;

//人类
public class Person {
    //属性:姓名,年龄和国籍,先不用私有
    String name ; //姓名
    int age ; //年龄
    //String country ;// 国籍
    static String country ;// 国籍

    //永远给出无参构造方法
    public Person(){}
    //给出有参构造方法  ---带两个参数
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }

    //带三个参的构造方法
    public Person(String name,int age,String country){
        this.name = name ;
        this.age = age ;
        this.country = country ;
    }

    //show方法,展示这个人具体信息
    public void show(){
        System.out.println("这个人姓名是:"+name+",年龄是:"+age+",所在的国籍是:"+country);
    }

}

代码块

代码块: 使用{}括起来的内容

  • 分类:	 局部代码块,就是在方法定义中使用{}
               {},作用:就是限定局部变量的生命周期;
    
  •  构造代码块:---在类的成员位置定义的{},它有特点:在执行构造方法之前,如果类中有构造代码块,优先执行构造代码块,作用:也可以给类的成员的数据进行初始化; (实际开发很少见到构造代码块)
    

*只要执行构造方法,如果存在构代码块,它必须优先执行,然后才是构造方法…
*

  •    静态代码块:类就加载一次,静态代码块也就执行一次!
    
  •           格式
                  static{ --->跟静态相关的都和类有关系,随着类的加载而加载;
                里面书写代码
                         }
    

继承

将多个类的共性内容抽取出来,放在一个独立的类中,让这个独立的类和其他类产生一种关系

  • “继承”—关键字 extends
    格式:

  •      class 父类名{
               共性内容:姓名,年龄.....
               提供公共的访问方法setXXX()/getXXX()
       }
        class 子类名 extends 父类名{
           }
    
  •      继承的好处:
            1)可以提高代码复用性
            2)可以提高代码的维护性,后期便于维护,针对子类和父类进行维护(子父关系明确)
            3)类与类产生的继承关系,是后面讲"多态"的前提条件;
    

在Java中有一个开发原则 “低耦合,高内聚”(以后所有的Java设计模式都需要遵循这一个原则)
*耦合性:开发中是永远避免不了,可以降低(耦合:类和类的关系)
*内聚性:指的是某个类完成某个功能的一种能力; 尽量不要产生继承关系来完成一个功能,一个类能完成一个类完成;

  • 低耦合:降低耦合性,减少类和类的关系;
    特点:
    1)在Java语言中,类和的类的关系是一种继承关系,这个继承只能支持"单继承",不支持多继承
  •              class 父{}
                 class 父2{}
                 class 子 extends 父,父2{} 多继承:不支持
                 class 子 extends 父{} :正常的语法格式
    

2)类和类关系,虽然不支持多继承,但是层层单继承----> 多层继承
关于的注意的问题:

  •  1.子类继承父类,对于非私有的成员,直接可以继承过来,但是如果私有成员,它可以通过公共的访问可以访问,但是直接访问的;
    2.被私有修饰的东西(成员变量/成员方法),只能在当前类访问的;
    
package com.qf.extends;
class Fu{
    //非私有的成员变量
    int num = 20 ;

    //私有的成员变量
    private int num2 = 50 ;

    //非私有的成员方法
    public void method(){
        System.out.println("method Fu...");

        System.out.println(num2);  //间接通过公共的访问访问了num2
    }
    //私有的成员的方法
    private void function(){
        System.out.println("function Fu...");
    }

    //定义一个公共访问方法
    public void function2(){
        function();  //间接访问了私有方法
    }
}
//子类
class Zi extends  Fu{
        //有一个自己的功能
    public void show(){
        System.out.println("show zi...");
    }
}

//测试类
public class ExtendsDemo3 {
    public static void main(String[] args) {

        //创建子类对象
        Zi zi  = new Zi() ;
        System.out.println(zi.num) ;
       // System.out.println(zi.num2) ;//num2在父类中已经被private控制了

        zi.method();
       // zi.function() ; //private的

        zi.function2();
    }

在继承关系中,构造方法的访问问题(重点)

  •  子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法为什么?
    

子类继承父类,会用到父类的数据,需要让父类先进行初始化; 一个类初始化的—肯定需要执行构造方法的

  • 面试题:
    如果一个父类存在有参构造方法,没有无参构造方法,子类的所有构造会出现什么问题?出现了问题,怎么解决?
    子类的所有全部构造方法报错,为什么?
    子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
    *方案1:
  • 1)手动给出无参构造方法
    2)假设,不能给出父类的无参构造方法;
     就需要让子类的构造方法,显示的访问父类的有参构造方法
    

要使用关键字super:代表父类空间标识(代表的父类对象的地址值引用!)
*

  •           super() :访问父类的无参构造方法
             super(xxx) :访问父类的有参构造方法
     这些super一定是在子类构造方法中的第一句话
    
    1. 保证子类的所有的构造方法某一个构造方法,让父类初始化完毕即可;
      先通过子类的无参构造方法里面
      this(xxx)
      访问本类(子类)有参构造方法
      在子类的有参构造方法的第一话:让父类初始化 super(xxx):间接访问父类的有参构造方法
      子类继承父类,一定要先执行父类的构造方法,初始化完毕之后;然后才能执行子类的构造方法—分层初始化
      继承关系中:所有的子类的构造方法默认访问父类的无参构造方法;
  • this和super的区别

  • this.变量名 :本类的成员变量

  • super.变量名: 父类的成员变量

  • this.方法名() ;本类的成员方法

  • super.方法名(); 父类的成员方法

  • this():访问本类的无参构造方法

  • super():访问父类的无参构造方法

  • this(XXX):访问的本类的有参构造方法

  • super(xxx):访问父类的有参构造方法

package com.qf.extends;
//父类
class Fu2{
    /*public Fu2(){
        System.out.println("这是Fu2的无参构造方法...");
    }*/
    public Fu2(String name){
        System.out.println("这是Fu2的有参构造方法...") ;
    }
}
//子类
class Zi2 extends Fu2{
    //给出Zi2的无参构造方法
    public Zi2(){
        //super("随便给") ;

        this("高圆圆") ; //访问本类的有参构造方法
        System.out.println("这是Zi2的无参构造方法...");
        //super("随便给") ; //一定是在第一句话
    }

    public Zi2(String name){
        super("随便给") ;
        System.out.println("这是Zi2的有参构造方法...");
    }
}
//测试类
public class ExtendsDemo4 {
    public static void main(String[] args) {

        //创建子类对象
        Zi2 z = new  Zi2() ; //访问子类的无参构造方法
      /*  System.out.println("---------------") ;
        Zi2 z2 = new Zi2("hello") ;*/
    }
}

子类继承父类,成员变量的访问问题;

  • 情况1: 子类和父类的中成员变量名称不一致,访问比较简单,分别访问即可!
    *情况2:子类和父类的成员变量名称一致: 如何访问呢?
  • 1)先在子类的局部位置找,有没有这个变量,有就使用;
  • 2)如果没有,在子类成员位置中找,有没有这个变量,有就使用;
  • 3)如果子类的成员位置也没有,然后会在父类的成员位置找,有没有这个变量,有就使用;
  • 4)如果父类的成员位置都没有,报错(前提:这个父类没有它的父类了),说明整个子父类中都没有变量;
    *遵循"就近原则"

子类继承父类,关于成员方法的访问问题*

  • 情况1:子类和父类的成员方法名称不一致,比较简单,分别调用即可;
  • 情况2:子类和父类的成员方法一模一样:权限修饰符,返回值类型,参数列表都一样
  • 子类将父类的方法覆盖了---->方法重写 :Override---->子类在父类的基础上,将父类的覆盖了,使用自己的功能;
    方法重载: 定义方法的时候,方法名相同,参数列表不同,与返回值无关; 目的为保证这个方法它的扩展性问题,同一个方法,可以不同类的参数;
    举例:
  •              动物都需要吃
    

猫类和狗类吃的东西不一样,将Animal类的eat进行重写;
面试题:
方法重写override和方法重载overload有什么区别?
方法重写:出现在继承中, 描述的子类继承父类的时候,可能沿用父亲的功能,而且使用
自己的功能,将父类的功能进行覆盖(复写/重写); 为了让子类具体体现出来的功能信息

final关键字

final关键字特点:

  • 本身的含义:最终的,无法更改的
  • 1)final可以修饰类,该类不能被继承
  • 2)final可以修饰变量,此时这个变量是一个"常量",常驻内存;
  •  自定义常量:在开发中:
     定义一个int类型的
          public static final 数据类型 xxx = 值;
          class Demo{
         public static final int x = 100 ; // 自定义常量:  编译时期常量,不需要加载;jvm检查语法即可
    
    //后期常用类:基本类型 int—> 自动提升 Integer 类
    public static final Integer i = new Integer(100) ; 运行时期常量,因为jvm需要加载Integer类
    }
    类名访问:
    Demo.x
    Demo.i
    3)final修饰成员方法,此时这个方法不能被子类重写,目的为了保证方法中某些数据的 安全
package com.qf.final_08;

/**
 * 类加载的时候,内存是很快的 继承关系
 * 父类和子类跟静态相关的先执行
 *
 * 静态的东西优先于对象存在 (类名 对象名 = new 类名() ;)
 *
 * 静态代码块>构造代码块>构造方法....
 *
 * 继承关系:分层初始化---->先父类初始化----然后才是子类初始化
 */


class Fu2{
    static{
        System.out.println("Fu2的静态代码块");//1)
    }
    public Fu2(){
        System.out.println("Fu2的无参构造方法");//4)
    }
    {
        System.out.println("Fu2的构造代码块");  //3)
    }
}
class Zi2 extends  Fu2{
    public Zi2(){
        System.out.println("Zi2的无参构造方法");//6)
    }
    {
      System.out.println("Zi2的构造代码块");   //5)
    }
    static{
      System.out.println("Zi2的静态代码块");    //2)
    }
}

//看程序,写结果
public class Test {
    public static void main(String[] args) {
        //创建子类对象
        Zi2 z = new Zi2() ;
    }
}

多态

什么是多态?

  • 多态:

  •  宏观角度(现实生活中):一个事物在不同时刻体现的不同形态
    水事物:
            气态,固态,液态
     猫是动物
     狗是动物
     微观角度(内存中变化):具体对象在内存中的变化(对象在不同时刻的类型)
    

    多态的前提条件 (重点)

  •      1)必须有继承关系(类与类),没有继承关系,不谈多态!
         2)必须存在方法重写,子类部分功能要将父类的功能进行覆盖,重写,子类使用自己的功能体现;
                举例:
                         动物都需要吃;
                        猫和狗/猪/猴子 等等  具体动物,给出具体的吃的体现,所以应该将动物的吃进行重写;
         3)必须存在父类引用指向 子类对象  :
    

固定格式

  •  父  父  =  new  子;
           class Fu{}
            class Zi extends Fu{}
      父类名 对象名  = new 子类名() ;   //向上转型:使用的父亲的东西
    
         Fu fu = new Zi() ; //父类引用指向 子类对象
    
       Animal a = new Cat() ;//Cat继承自Animal      猫是动物
    

多态的成员访问特点(很重要)
父类名 对象名 = new 子类名() ;
1)成员变量:
编译看左,运行看左 ;
2)成员方法 :
非静态方法:
编译看左,运行看右, 因为子类重写了父类的功能!
静态方法: 即使子类出现了和父类一模一样静态方法,不算重写,因为静态方法都是自己类相关的,类成员!
编译看左,运行看左;
3)构造方法:多态的前提条件,有继承关系,跟继承一样,分层初始化
先执行父类的构造方法,然后再是子类的构造方法

多态的好处:
1)提高代码的复用性,由继承保证的
2)提高代码的扩展性,由多态保证 : 父类引用指向子类对象
多态的弊端:

  •  1)有继承关系了 
     2)有重写了 
     3)有父类引用指向子类对象 Fu f = new Zi() ;但无法调用子类的特有功能!
    

如何解决呢?

  • 方案1:创建自己的子类对象
  •     子类名 对象名 = new 子类名() ;
        方案1不好地方:本身Fu fu = new Zi() ;已经开辟堆内存空间了,
        Zi zi = new Zi();又要在堆内存开辟空间,消耗内存空间比较大 ;
    

*方案2: 向下转型
多态的第三个前提条件:父类引用指向子类对象

  •  能不能将 将父类的引用 强制为子类的引用呢?
               可以:
      向下转型(前提必须向上转型Fu fu = new Zi() ;)
       ***格式:     Zi z  = (Zi)fu ;  //强转的语法***
    

这样的好处:节省内存空间
针对多态的向下转型,前提必须有向上转型(父类引用指向子类对象)

0多态的里面的向下转型使用不当_会出现ClassCastException类转换异常

package com.qf.oop_duota;
class Fu{
    public void show(){
        System.out.println("show Fu");
    }
}
//子类
class Zi extends  Fu {
    public void show() {
        System.out.println("show Zi");

    }

    //子类有自己的特有功能
    public void playGame(){
        System.out.println("会玩lol");
    }
}
//测试类
public class DuoTaiDemo2 {
    public static void main(String[] args) {
            //父类引用指向子类对象
        Fu fu = new Zi() ;
        fu.show() ;//编译看左,运行看右
       // fu.playGame() ; //编译看左,运行看右

        //方案1
        Zi zi = new Zi() ;//创建子类具体对象
        zi.playGame();
        System.out.println("--------------------------------") ;
        //子类名  对象名  =  (子类型)父类对象;  //向下转型
        //方案2
        Zi z = (Zi) fu;//分号后面alt+enter ---回车 自动补全
        z.playGame();
    }

抽象

什么抽象类?
在一个类中,如果有抽象方法,这个类必须为抽象类

举例:

  • 现实生活中,说到动物或者人—>这些事物都是概括性的,这些概括性的事物中都有自己的行为
  • 动物都需要吃,但是只有见到具体的事物,才知道具体的动物吃什么类型食物,在代码定义动物类的时候,在吃个行为上不应该只给出具体体现(仅仅给出一个功能的声明),而是应该具体体现在具体的动物类中(动物类的子类);
  • 给某个事物的一些行为,不给出具体体现,在Java编程中,应该加入一个关键字 abstract,这些行为—>“抽象方法”
  • 有抽象方法的类一定是抽象类,

抽象的方法的格式:
根据写方法的格式一样,加入一个关键字abstract,而且没有方法体{}
public abstract 返回值类型 方法名(空参/带参) ;

抽象类的特点:
1)不能实例化 (不能创建对象)
2)必须强制子类完成事情:必须将抽象方法重写!

*抽象类的子类:

  •  如果子类是一个抽象类,  没有意义(抽象类new不了) (前提条件是这个子类没有它的子类)
     研究的抽象类的子类一定会有一个具体类,这个时候通过具体类才能创建对象;
    
     抽象的父类名  对象名  = new 具体的子类名() ;  抽象类多态
    

抽象类的成员特点:
成员变量:抽象类的成员变量既可以有变量,也可以是自定义常量被final
成员方法:抽象类中既可以有抽象方法,也可也有非抽象方法
构造方法:
既可以定义无参/有参构造方法…
存在抽象类多态,有继承关系,初始化的时候,构
造方法----分层初始化---->先父类初始化,子类初始化
面试题:
如果有一个类没有任何的抽象方法,还要将这个类定义为抽象类的意义?
意义:意义就是不能让它new,它如何实例化呢?肯定有具体的子类,进行抽象类多态来操作…
设计代码(设计层面)

package com.qf.abstract;
abstract  class Person{ //抽象类

    //定义一个成员变量
    public int num = 100 ;   //变量

    public final int num2 = 200 ;  //自定义常量  num2不能在改变

    //人都要学习---具体的人才具备具体的动作行为----方法抽象化
    public abstract  void study();

    //无参构造方法
    public Person(){
        System.out.println("这是Person类的无参构造方法");
    }

    public void method(){//非抽象方法
        System.out.println(num) ;
        System.out.println(num2);
    }
}
//学生类
class Student extends  Person{

    //无参构造方法
    public Student(){
        System.out.println("这是Student的无参构造方法");
    }

    @Override
    public void study() {
        System.out.println("学生主要目的学习专业知识");
    }
}

//测试类
public class AbstractDemo2 {
    public static void main(String[] args) {

        //抽象类多态测试
        Person p = new Student() ;
        p.method();

        p.study() ;
    }
}

面试题
问题1 : abstract 和那些关键字冲突

  •  和private关键字冲突:因为被private私有的成员方法只能在本类访问,而abstract修饰的成员方法必须强制子类重写,已经超出来的当前类的范围
     和final冲突,被final修的成员方法,不能被重写;而抽象方法强制子类必须重写;
     和static也冲突,abstract修饰的方法必须被子类重写,而static修饰的方法,算不上抽象,直接跟类相关的;
    

*abstract关键字 应用范围: 定义在类上—抽象类

  • 定义在方法上----抽象方法
    public abstract 返回值类型 方法名(空参/带参…) ;
    abstract 返回值类型 方法/名(空参带参…) ;

问题2:
子类继承父类,子类重写父类的抽象方法,必须保证访问权限足够大,要么加public要么跟父类的方法保持一致!
否则报错;

接口

什么是接口?

  • 接口体现的是事物的一种额外功能 ;
  • 设计理念: 体现的是一种 "like a"的关系
    跳高猫
    钻火圈狗
    之前讲继承的概念—>设计理念体现的是一种"is a"的关系 :什么是什么的一种
    水果
    香蕉
    苹果
    橘子
    接口—体现事物本身以外的额外功能,需要事物要对接口的功能要进行实现,才具备!
    *接口的定义
    interface 接口名{} 接口和类名的命名规范同理,遵循"大驼峰命名法"
    接口的最大特点: 不能实例化
    如何实例化?
    接口通过它的子实现类进行实例化(前提,这个类实现 implements 接口)
  • class 子实现类名 implements 接口名{//实现
    }
    实际开发中:接口的子实现类名的命名—> 接口名的后面+Impl:表示是接口的实现类

接口的成员特点:
1)成员变量:只能是常量,存在默认修饰符 :public static final
2)成员方法:只能是抽象方法,存在默认修饰符 public abstract
3)构造方法:没有构造方法的—通过子实现类的构造方法来实例化

     接口本身意义:对外暴露这些功能,让子实现类实现 !

Java编码中,体现这些事物本身不具备的功能,要经过一些特殊的实现才能具备功能-----称为 “接口”—关键字 interface

  •  格式的写法
            interface  接口名{   //命名规范和类名命名一样,见名知意 "大驼峰命名法"
                        只能为抽象方法
                }
    
               接口的子类----"子实现类"
                            实现
               class 子类名  implements  接口名{
               }
     接口比抽象类还抽象---->特点:不能实例化
    
package com.qf.interface;
interface Jump{
    /*public void jump(){  //接口中的只能是抽象方法

    }*/
    public abstract void jump() ;//因为 它默认修饰符 public abstract:可以省略不写
}
//跳高猫
 class Cat  implements  Jump{

    @Override
    public void jump() {
        System.out.println("猫可以跳高了");
    }
}

//测试类
public class InterfaceDemo {
    public static void main(String[] args) {

        //Jump jump2  = new Jump() ;//接口不能实例化,需要通过子实现类实例化(必须为具体类)
        //测试:接口多态---接口名 对象名 = new 子实现类名();
        Jump jump = new Cat() ;
        jump.jump();
    }
}

孔子装爹_加深理解多态的成员访问特点

接口和抽象类的区别(面试题)
1)成员的区别
成员变量:
抽象类:
可以是变量,也可以是自定义常量
接口: 成员变量只能是常量: 存在默认修饰符 public static final 修饰的 ,可以省略
成员方法
抽象类:
即可以是抽象方法,也可以是 非抽象方法
接口:
只能是抽象方法,存在默认修饰符:public abstract :可以省略
构造方法
抽象类:
既可以存在无参构造方法/有参构造方法,存在继承关系,分层初始化先父类初始化,再是子类初始化(子类需要用到父类中)
接口:没有构造方法的 ,意义:就是通过接口暴露给外面功能,实现这些功能接口
2)关系区别
Java中最基本的单元是类,Java本身就面向接口编程
类和类:继承关系 extends,Java语言中只支持单继承,不支持多继承,但是可以多层继承
类和接口: 实现关系 implements;一个类继承另一个类的同时,可以实现多个接口
接口和接口:继承关系:extends 不仅支持单继承,也可以多继承!
3)设计理念的区别
抽象类:
存在继承关系, 体现的是一种"is a"的关系 ,什么是什么的一种A类是B类的一种,B类是A类的一种 ,这个时候要使用继承;
接口:
子实现类 实现关系,体现的一种"like a"的关系,什么像什么的一种额外的扩展功能 ;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值