Java学习笔记Week_03

static关键字的特点

1)被静态修饰的随着类的加载而加载,优先于对象存在;
2)不能和this共存;
3)本身含义就是共享,共用;可以和多个对象共用;
4)被静态修饰的成员变量或者成员方法(静态变量/静态方法)的访问方式:
    对于系统(jvm)来说静态的方法/变量都是类名直接访问;类名.变量名/类名.方法名()
    也可以使用对象名来访问;

静态的使用场景适用范围
静态只能访问静态;
静态方法中只能访问静态变量;
静态方法只能调用静态方法;
非静态方法可以访问静态也可以访问非静态的东西;

生成数组工具说明书文档

/**
 *ArrayTool类是针对数组操作的工具类,里面包含了数组的遍历功能,求数组最值问题,
 * 获取数组的元素第一次出现索引值,冒泡排序等提供很多功能;
 * @author ZhangYang
 * @version V1.0
 */
public class ArrayTool {

    //提供一个私有的构造方法,为了外界不能直接new
    private ArrayTool(){}

    //遍历数组---->此时构造方法私有化了,必须在成员方法里面加入一个关键字static

    /**
     * 这个方法是针对数组的遍历功能,将数组按照指定格式输出,输出格式如下:
     * [元素1, 元素2, 元素3, 元素4,....元素n]
     * @param arr 要传递的真实数组(要遍历的数组对象)
     */
    public static void printArray(int[] arr){ //形式参数---引用类型,数组类型,需要传递这个数组的对象
        System.out.print("[");
        for(int x = 0 ; x <arr.length ; x ++){
            //如果x角标取到最大索引值
            if(x==arr.length-1){
                System.out.println(arr[x]+"]");
            }else{
                System.out.print(arr[x]+", ");
            }
        }
    }

    /**
     * 这个方法是获取数组中的最大值;
     * @param arr 要传递数组对象,在这里面查询最大值
     * @return 返回数组中的最大值
     */
    public static int getMax(int[] arr){
        //参照物
        int max = arr[0] ;
        for(int x =1; x <arr.length ;x++){
            if(arr[x]>max){
                max = arr[x] ;
            }
        }
        return  max ;
    }

    /**
     * 这个方法是获取数组中第一次出现索引值
     * @param arr 要查询的数组
     * @param key 要查找在数组中的指定的元素
     * @return 返回的就是数组的元素第一次出现的索引值,否则,返回-1
     */
    public static int getIndex(int[] arr,int key){
        //假设
        int index = -1 ;
        //遍历数组
        for(int x = 0 ; x <arr.length ; x ++){
            if(key == arr[x]){
                index = x ;
                break ;
            }
        }
        return  index ;
    }

    /**
     * 这个方法是对数组进行冒泡排序
     * @param arr 要将数组进行排序
     */
    public static void bubleSort(int[] arr){
        for(int x = 0 ; x < arr.length -1 ; x ++){
            for(int y = 0; y < arr.length-1-x; y++){
                if(arr[y] >arr[y+1]){
                    //互换
                    int temp = arr[y] ;
                    arr[y]  = arr[y+1] ;
                    arr[y+1] = temp ;
                }
            }
        }
    }
}

代码块

使用{}括起来的内容
分类:
局部代码块,就是在方法定义中使用{}
{}作用,就是限定局部变量的生命周期;

构造代码块—在类的成员位置定义的{},它有特点:在执行构造方法之前,如果类中有构造代码块,优先执行构造代码块,作用:也可以给类的成员的数据进行初始化;
执行构造方法时,如果存在构造代码块,必须优先执行,然后才是构造方法…

静态代码块

类加载一次,静态代码块就执行一次.
格式
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.被私有修饰的东西(成员变量/成员方法),只能在当前类访问的;

在继承关系中,构造方法的访问问题(重点)
子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
为什么?子类继承父类,会用到父类的数据,需要让父类先进行初始化; 一个类初始化的—肯定需要执行构造方法的
面试题:
如果一个父类存在有参构造方法,没有无参构造方法,子类的所有构造会出现什么问题?出现了问题,怎么解决?
子类的所有全部构造方法报错,为什么? 子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法

方案:
1)手动给出无参构造方法
2)假设,人家现在就不需要让你给出父类的无参构造方法;
就需要让子类的构造方法,显示的访问父类的有参构造方法
----要使用关键字 super:代表父类空间标识(代表的父类对象的地址值引用!)
super() :访问父类的无参构造方法
super(xxx) :访问父类的有参构造方法
这些super一定是在子类构造方法中的第一句话
方案3) 保证子类的所有的构造方法某一个构造方法,让父类初始化完毕即可;
先通过子类的无参构造方法里面—this(xxx):访问本类(子类)有参构造方法

  •   在子类的有参构造方法的第一话:让父类初始化 super(xxx):间接访问父类的有参构造方法
    
  •   子类继承父类,一定要先执行父类的构造方法,初始化完毕之后;然后才能执行子类的构造方法---分层初始化
    

面试题(看程序,写结果)

需要在控制台分别打印30,20,10

//考点:子类关系问题,子类和父类的成员变量一致,访问变量的流程;---->就近原则

/**
 * this和super的区别
 * this:代表的当前类对象的地址值引用
 * super:代表的父类的空间标识(父类的对象的地址值引用)
 *
 * this.变量名 :访问本类的成员变量
 * super.变量名:访问的父类的成员变量
 *
 * this.方法名():访问本类的成员方法
 * super.方法名():访问父类的成员方法
 *
 * this():访问本类无参构造方法
 * this(xxx):访问的是本类的有参构造方法
 *
 * super():访问父类的无参构造方法
 * super(xxx):访问的父类的有参构造方法
 */
class Test{
    public static void main(String[] args){
        Zi zi = new Zi();
        zi.show() ;
    }
}

class Fu{
    int num = 10;
}
class Zi extends Fu{
    int num = 20 ;
    public void show(){
        int num = 30 ;
        //补全代码
        System.out.println(num);
        System.out.println(this.num) ;//访问本类的成员变量 :this限定:本类的东西
        System.out.println(super.num); //访问的父类的成员变量:super限定:父类的东西
    }
}

子类继承父类,成员变量的访问问题;
情况1: 子类和父类的中成员变量名称不一致,访问比较简单,分别访问即可!
情况2:子类和父类的成员变量名称一致: 如何访问呢?

  • 1)先在子类的局部位置找,有没有这个变量,有就使用;
  • 2)如果没有,在子类成员位置中找,有没有这个变量,有就使用;
  • 3)如果子类的成员位置也没有,然后会在父类的成员位置找,有没有这个变量,有就使用;
  • 4)如果父类的成员位置都没有,报错(前提:这个父类没有它的父类了),说明整个子父类中都没有变量;
    遵循"就近原则"

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

  • 情况1:子类和父类的成员方法名称不一致,比较简单,分别调用即可;

  • 情况2:子类和父类的成员方法一模一样:权限修饰符,返回值类型,参数列表都一样
    子类将父类的方法覆盖了---->方法重写 :Override---->子类在父类的基础上,将父类的覆盖了,使用自己的功能;

    举例:
    动物都需要吃
    猫类和狗类吃的东西不一样,将Animal类的eat进行重写;

*/

//父类
class Fu{
    //父类的成员方法
    public void show(){
        System.out.println("show Fu...");
    }
    //有一个方法
    public void teach(){
        System.out.println("会JavaEE...");
    }

   /* public void method(){
        System.out.println("method Fu...");
    }*/
}
//子类
class Zi extends  Fu{
    //子类的成员方法
    public void function(){
        System.out.println("function Zi...");
    }

    //直接将父类的方法覆盖了
    //子类和父类出现的一模一样的方法
    public void teach(){//override
        super.teach();  //不仅沿用父亲的功能,
        System.out.println("会Python,会前端,会管理项目...");
    }


    //子类的成员method
   /* public String method(){ //系统认为父类的方法名也是method,必须加上返回值
        return "hello" ;
    }*/
}
//测试类
public class ExtendsDemo {
    public static void main(String[] args) {

        //创建子类对象
        Zi z = new Zi() ;
        z.show();//访问父类的方法
        z.function();

        z.teach() ;
    }
}

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修饰成员方法,此时这个方法不能被子类重写,目的为了保证方法中某些数据的 安全性!

/**
 * 需求:
 *        父类中有一个方法,描述一件事情:"这个是绝密文件,任何不得更改"
 *        子类如果出现了和父类一模一的方法,会将父类的方法覆盖掉,使用代码体现;
 *
 *  在有的情况里面,父类的功能不能让子类覆盖 ,Java提供了一个关键字"final"
 *
 *  final:最终的,无法更改的,状态修饰符 ,被final修饰的成员方法,不能被重写,保证父类的方法安全性!
 */

class Fu{
//    public  void function(){
    public final void function(){
        System.out.println("这个是绝密文件,任何不得更改");
    }
}
//子类继承父类
class Zi extends  Fu{
   /* public void function(){
        System.out.println("这是一堆垃圾...");
    }*/
}
//测试类
public class FinalDemo {
    public static void main(String[] args) {

        //创建子类对象
        Zi z = new Zi() ;
        z.function();
    }
}

多态

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

  •      1)必须有继承关系(类与类),没有继承关系,不谈多态!
    
  •       2)必须存在方法重写,子类部分功能要将父类的功能进行覆盖,重写,子类使用自己的功能体现;
        
      举例:
            动物都需要吃;
           猫和狗/猪/猴子 等等  具体动物,给出具体的吃的体现,所以应该将动物的吃进行重写;
    
  •      3)必须存在父类引用指向 子类对象  :固定格式
            class Fu{}
            class Zi extends Fu{}
            父类名 对象名  = new 子类名() ;   //向上转型:使用的父亲的东西
    
       Fu fu = new Zi() ; //父类引用指向 子类对象
       Animal a = new Cat() ;//Cat继承自Animal      猫是动物
    
       举例
               猫和狗都继承自动物类
              动物类---eat()---->动物饿了都需要吃饭
                        sleep()---->动物困了就需要休息...
    

多态的成员访问特点(很重要)
父类名 对象名 = new 子类名() ;

  • 1)成员变量:

         编译看左,运行看左 ;
    
  • 2)成员方法 :非静态

           编译看左,运行看后, 因为子类重写了父类的功能!
    
           静态方法: 即使子类出现了和父类一模一样静态方法,不算重写,因为静态方法都是自己类相关的,类成员!
           编译看左,运行看左;
    
  • 3)构造方法:多态的前提条件,有继承关系,跟继承一样,分层初始化

          先执行父类的构造方法,然后再是子类的构造方法
    
//动物类
class Animal{
    int age = 50  ;
    public Animal(){
        System.out.println("Animal的无参构造方法");
    }
    public void eat(){
        System.out.println("动物饿了都需要吃饭");
    }
    public void sleep(){
        System.out.println("动物困了就需要休息");
    }

    //父类的静态方法
    public static void show(){
        System.out.println("show Animal");
    }
}
//猫类
class Cat extends  Animal{
    int age = 20 ;
    public Cat(){
        System.out.println("Cat的无参构造方法");
    }
        //将eat和sleep()具体体现,应该重写父类的方法

    public static void show(){
        System.out.println("show Cat");
    }
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫躺着睡");
    }
}
//狗类
class Dog extends  Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }

    @Override
    public void sleep() {
        System.out.println("狗侧着睡...");
    }
}
//测试类
public class DuoTaiDemo {
    public static void main(String[] args) {

        //多态进行测试:
        //父类引用指向 子类对象  :固定格式
        //父类名 对象名  =new 子类名() ;


        Animal a = new Cat() ; //堆内存存储的猫   猫是动物
        System.out.println(a.age) ;// 编译看左,运行看左 ;
        a.eat(); //编译看左,运行看右 (前提存在重写)
        a.sleep();编译看左,运行看右 (前提存在重写)

        //调用静态show
        //a.show() ; //编译看左,运行看左---show方法是静态,不推荐使用对象访问,类名访问
        Animal.show();
        Cat.show();

      /*  Animal a2 = new Dog() ; //狗是动物    堆内存中存储的是狗
        a2.eat();
        a2.sleep();*/
    }
}

多态的弊端:
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 ; //强转的语法
    这样的好处:节省内存空间
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKPQ4UYd-1660383081650)(en-resource://database/572:1)]

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();
    }
}

多态的好处:

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

如果在使用多态时出现 ClassCastException,说明什么?

ClassCastException :属于运行时期异常的一种; 代表"类转换异常"
使用多态操作向下转型的时候(使用不当),堆内存中 信息和栈内存信息没有子父关系

        Animal a = new Cat() ; //堆内存是猫 猫是动物 
        //Cat c = (Cat)a; //还原成猫 猫是猫 
        Dog d = (Dog)a ;//语法没有问题,但是内存中有问题 (猫是狗,错误的)

抽象

有抽象方法(在具体的事物中才能能具体的行为)的类一定是抽象类; public abstract 返回值类型(参数类型 形式名称.,...) ; 

抽象类的成员特点:

  • 成员变量:可以是变量,也是自定义常量

  • 成员方法:可以存在抽象方法,也可以存在非抽象方法

  • 构造方法:可以存在无参/有参构造方法;分层初始化:先父类初始化,然后再是 子类初始化;

  • 抽象类不能实例化:不能new对象 所以通过抽象类多态来实例化,通过具体的子类进行实例化 抽象类名 对象名 = new 具体的子类名() ;

abstract不能和哪些关键字使用

抽象类不能实例化,而且它是强制子类必须重写抽象方法;

  • abstract不能和 static使用:
    static被类名访问.跟类相关,静态方法算不上方法重写;

  • 不能和private使用:
    被private修饰的:只能在当前类访问 而abstract修饰的方法需要被子类重写

  • 不能和final使用
    被final修饰的成员方法,不能被重写; (有的jdk源码中会看到) abstract修饰的方法必须子类重写;

接口

接口的定义

       interface 接口名{}   接口和类名的命名规范同理,遵循"大驼峰命名法"
 接口的最大特点: 不能实例化

*  如何实例化?
    接口通过它的子实现类进行实例化(前提,这个类实现 implements 接口)
  class 子实现类名 implements 接口名{//实现 }
  • 接口: 体现的是一种额外功能, 设计理念 "like a"的关系
  • 接口和子实现类的关系:implments 实现
//接口 
 interface Mary{ //成员方法:只能是抽象方法 
        public abstract void mary() ; } //子实现类 
     class You implements Mary{ public viod mary(){ System.out.println("结婚了,很开心....") ; 
      }
}

class Test{ public static void main(String[] args){ 
     //接口比抽象类还抽象:抽象类都不能直接new对象,接口也不能 实例化 
     //接口多态:接口名 对象名 = new 子实现类名() ; 
     Mary mary = new You() ; 
     mary.mary() ;
     }
}

接口的成员特点

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

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

关于面向对象中牵扯关系问题:
Java中最基本的单元是类

  •  类和类:继承关系 extends,Java语言中只支持单继承,不支持多继承,但是可以多层继承
    
  •  类和接口: 实现关系 implements;一个类继承另一个类的同时,可以实现多个接口
    
  •  接口和接口:继承关系:extends   不仅支持单继承,也可以多继承!
    

接口和抽象类的区别(面试题)

1)成员的区别

  • 成员变量:
    抽象类: 可以是变量,也可以是自定义常量
    接口: 成员变量只能是常量: 存在默认修饰符 public static final 修饰的 ,可 以省略

  • 成员方法
    抽象类: 即可以是抽象方法,也可以是 非抽象方法
    接口: 只能是抽象方法,存在默认修饰符:public abstract :可以省略

  • 构造方法
    抽象类: 既可以存在无参构造方法/有参构造方法,存在继承关系,分层初 始化 先父类初始化,再是子类初始化(子类需要用到父类中)
    接口:没有构造方法的 ,意义:就是通过接口暴露给外面功能,实现这些功能 接口

2)关系区别
Java中最基本的单元是类,Java本身就面向接口编程
类和类:继承关系 extends,Java语言中只支持单继承,不支持多继承,但是可以多 层继承

类和接口: 实现关系 implements;一个类继承另一个类的同时,可以实现多个接口

接口和接口:继承关系:extends 不仅支持单继承,也可以多继承! 

3)设计理念的区别
抽象类: 存在继承关系, 体现的是一种"is a"的关系 ,什么是什么的一种 A类是B类的一种,B类是A类的一种 ,这个时候要使用继承;
接口: 子实现类 实现关系,体现的一种"like a"的关系,什么像什么的一种 额外的扩展功能 ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值