java语言学习(5)

第九章

目录

  • 类变量和类方法

  • 理解main方法语法

  • 代码块

  • 单列设计模式

  • final关键字

  • 抽象类

  • 接口

类变量/静态变量

该变量最大的特点就是会被本类的所有对象实例共享,类变量可以通过类名来访问

分析代码,探讨内存的分配

    class Child{
        private String name;
        public static int count = 0;
        //这个叫类变量或者叫静态变量
        public Child(String name){
            this.name = name;
        }
        public void join(){
            System.out.println(name+"加入了游戏");
        }
    }

在jbk8之前,我们认为是放在静态域里面的。

在jbk8之后,我们认为是放在堆里的。

java语言学习(5)_第1张图片

不管static变量在哪里

  • static变量是同一个类所有对象共享

  • static类变量,在类加载时候就生成了

定义:类变量也叫静态变量/静态数学,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,统一任何一个该类的对象去修改它时,修改的也是同一个变量

语法

访问修饰符 static 数据类型 变量名; 【推荐】

static 访问内修饰符 数据类型 变量名;

访问

类名.类变量名 【推荐】

对象名.类变量名

【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】

类变量细节

  • 当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量),比如:定义学生类,统计所有学生共交多少钱

  • 类变量是该类的所有对象共享的,而实例变量是每个对象独享的

  • 加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量

  • 类变量可以通过类名.类变量名 或者 对象名.类变量名 来访问,但java设计者推荐我们使用 类名.类变量名方式访问。【前提,满足访问修饰符的访问权限和范围】

  • 实例变量不能通过 类名.类变量名 方式访问

  • 类变量是在加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了

  • 类变量的生命周期是随类的加载开始,随着类消亡而销毁

注:静态变量是类加载的时候,就创建了,所以我们没有创建对象实例,也可以通过类名.类变量名来访问

类方法/静态方法

语法

访问修饰符 static 数据返回类型 方法名(){} 【推荐】

static 访问修饰符 数据返回类型 方法名(){}

调用

类名.类方法名

对象名.类方法名

说明

当方法使用了static修饰后,该方法就是静态方法

静态方法可以访问静态属性/变量

类方法的使用场景

  • 当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率

  • 比如根据类中的方法utils

    • Math类

    • Arrays类

    • Collections集合类

  • 如果我们不希望创建实例,也可以调用某个方法(即当作工具来使用),这时把方法做成静态方法非常合适

小结:程序员实际开发,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用了,比如打印一维数组冒泡排序,完成某个计算任务…

类变量和类方法 注意事项

  • 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区

    • 类方法中无this的参数

    • 普通方法中隐含着this的参数

  • 类方法中只能访问静态变量 或静态方法

  • 类方法可以通过类名调用,也可以通过对象名调用

  • 普通方法和对象有关,需要通过对象名来调用

理解main方法语法

  • main方法是虚拟机调用

  • java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public

  • java虚拟机在执行main()方法是不必创建对象,所以该方法必须是static

  • 该方法解释String类型的数组参数,该数组中保存执行java命令时传递给所允许的类的参数

特别提醒

  • 在main()方法中,我们可以直接调用main方法所在类的静态方法或静态属性

  • 但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员

代码块

定义:代码块又称为初始化块,属于类中的成员(是类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来

与方法的差别:没有方法名,没有返回,没有参数,只有方法体,而且不能通过对象或类现实调用,而创建对象时隐式调用

基本语法

修饰符{

代码

};

说明

  • 修饰符可选,要写的话,自能写static

  • 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块

  • 逻辑语句可以为任何逻辑语句(输入,输出,方法调用,循环,判断)

  • ;好可写,可不写

理解

  • 相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作

  • 场景:如果多个构造器都要重复语句,可以抽取到初始化块中,提高代码的重用性

  • 不管调用哪个构造器,创建对象,都会先调用代码块的内容

细节1

  • static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象就会执行一次

  • 类声明时候被加载

    • 创建对象实例时(new)

    • 创建子类对象实例,父类也会被加载

    • 使用类的静态成员时(静态属性,静态方法)

  • 普通的代码块,在创建对象实例时,会被隐式调用,被创建一次,就会调用一次。如果只是使用的类的静态成员时,普通代码块并不会执行

小结:

  1. static代码块是类加载时执行,所以只会执行一次

  2. 普通代码块时在创建对象时调用的,创建一次,调用一次

  3. 类加载的3种情况,需要记住

细节2(调用顺序)

  • 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码和多个静态变量初始化,则按他们定义的顺序调用)

  • 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化的第哦啊用优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)

  • 调用构造方法

小结:静态 > 普通 > 构造

细节3(构造器)

  • 构造器的最前面其实隐含了 super() 和 调用普通代码块
    class A{
        public A(){
            //这里有隐藏执行要求
            //(1)super
            //(2)调用普通代码块
            //(3)执行构造器
        }
    }

细节4(继承关系)

  1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)

  2. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)

  3. 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

  4. 父类的构造器

  5. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

  6. 子类的构造器

单例设计模式

设计模式:是在大量的实践种总结和理论化之后的优选代码结构,编程风格,以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索

单例模式:所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得对象实例的方法

  • 单例模式

    • 饿汉式

      • 构造器私有化,防止直接new

      • 类的内部创建对象

      • 向外暴露一个静态的公共方法

      class GirlFriend{
          private String name;
          //单例模式----饿汉式
          //1.将构造器私有化
          //2.在类的内部直接创建对象(该对象是static)
          //3.提供一个公共的static方法,返回gf对象
          private static GrilFriend gf = new GirlFriend("好人");
          private GrilFriend(String name){
              this.name = name;
          }
          public static Grilfriend getInstance(){
              return gf;
          }
      }
      //饿汉式创建的对象一般是重量级对象
      //饿汉式创建了对象,可能会使用不到
  • 懒汉式

    • 构造器私有化

    • 定义一个static静态属性对象

    • 提供一个public的static方法,可以返回一个Cat对象

    • 懒汉式,只有当用户使用getInstance时,才返回cat对象,面对再次调用时,会返回上次创建的cat对象,从而保持了单例

      class Cat{
          private Cat(String name){
              this.name = name;
          }
          public static Cat getInstance(){
              if(cat == null){
                  cat = new Cat("好人");
              }
              return cat;
          }
      }

饿汉式和懒汉式之间的区别

  • 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建

  • 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。

  • 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题

  • 在我们javaSE标准类中,Java.lang.Runtime就是经典的单例模式

final关键字

final可以修饰类,属性,方法,局部变量。

使用final的情况

  • 当不希望类被继承时,可以用final修饰

  • 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰

  • 放不希望类的某个属性的值被修改,可以用final修饰

  • 当不希望某个局部变量被修改,可以使用final修饰

细节

  • final修饰的属性又叫常量,一般用 XX_XX来命名

  • final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一

    • 定义时

    • 在构造器中

    • 在代码块中

  • 如果final修饰的属性是静态的,则初始化的位置只能是

    • 定义时

    • 在静态代码块

    • 注:不能在构造器中赋值

  • final类不能继承,但是可以实例化对象

  • 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承

  • 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法

  • final不能修饰构造方法(构造器)

  • final和static往往搭配使用,效率更高,底层编译器做了优化处理。(不会做类的加载)

  • 包装类(Integer,Double,Float,Boolean等都是final),String也是final类

    //例题
    public class Something{
    public int addOne(final int x){
    ++x;//错误的写法
    return x+1; //正确
    }
    }

抽象类

用法:当父类的某些方法,需要声明,但是于不确定如何实现时,可以将器声明为抽象方法,那么这个类就是抽象类

  • 所谓的抽象方法,就是没有实现的方法(没有方法体)

  • 当一个类中存在抽象方法时,需要将该类声明为抽象类

  • 一般来说,抽象类会被继承,由其子类来实现

介绍

  • 用abstract 关键字来修饰一个类时,这个类就叫抽象类

    • 访问修饰符 abstract 类名{}
  • 用abstract关键字来修饰一个方法时,这个方法就是抽象方法

    • 访问修饰符 abstract 返回类型 方法名(参数列表);

    • 没有方法体

  • 抽象类的价值更多资源是终于设计,是这记者设计好后,让子类继承并实现抽象类()

  • 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多

细节

  • 抽象类不能被实例化

  • 抽象类不一定要包含abstract方法,也就是说,抽象类可以没有abstract方法

  • 一旦类包含了abstract 方法,则这个类必须声明为abstract

  • abstract 只能修饰类和方法,不能修饰属性和其他的

  • 抽象类可以于任意成员【抽象类还是类】,比如:非抽象方法,构造器,静态属性…

  • 抽象方法不能有主体

  • 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类

  • 抽象方法不能使用private,final,static来修饰,因为这些关键子都是和重写相违背的

抽象类最佳实践-----模板设计模式

需求

  • 有多个类,完成不同的任务job

  • 要求能过得到各自完成任务的时间

补充知识:得到时间函数


    long start System.currentIimeMillis();
    
    ....
    
    long end System.currentIimeMillis();
    System.out.println(end - start)

模板设计如下

    public class data01 {
        public static void main(String[] args) {
            worker worker = new worker();
            worker.Time();
        }
    }
    
    abstract class Tool{
        public abstract void job();
        public void Time(){
            long time = System.currentTimeMillis();
            job();
            long time2 = System.currentTimeMillis();
            System.out.println("工作时间为" + (time2 - time));
        }
    }
    
    class worker extends Tool{
        public void job(){
            long all = 0;
            for (int i = 0; i < 1000; i++) {
                for (int j = 0; j < 1000; j++) {
                    all++;
                }
            }
            System.out.println(all);
        }
    }

接口

介绍:接口就是给出一些没有实现的方法,封装到一起,到某个类要使用时候,在根据具体情况把这些方法写出来,语法如下

    public interface 接口名{
    
        //属性
    
        //方法
    
    }
    //在接口中,抽象方法可以省略abstruse关键字
    
    class 类名 implements 接口{
    
        自己的属性
    
        自己的方法
    
        必须实现的接口的抽象方法
    
    }
    //如果一个类implements 实现接口
    //需要将该接口的所有抽象方法都实现
  • 在Jdk 7 前 接口里的所有方法都没有方法体,即都是抽象方法

  • jdk8 后接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。实现默认方法时需要使用default关键字修饰。

    //接口的实现
    public class data01 {
        public static void main(String[] args) {
            Dog dog = new Dog();
            Dog.text(dog);
        }
    }
    interface Too{
        public void speak();
        public void cry();
    }
    
    class Dog implements Too {
        public void speak(){
            System.out.println("Dog!");
        }
        public void cry(){
            System.out.println("汪汪汪汪!!!");
        }
        public static void text(Too too){
            too.speak();
            too.cry();
        }
    }

细节

  • 接口不能被实例化

  • 接口中使用的方法哦都是public方法,接口中抽象方法,可以不用abstract修饰

  • 一个普通类实现接口,就必须将该接口的所有方法都实现

  • 抽象类实现接口,可以不用实现接口的方法

  • 一个类同时可以实现多个接口

    • class Pig implements IB,IC{}
  • 接口中的属性,只能是final的,而且是public,static,final 修饰符

    • int a = 1;

    • 实际上是 public static final int a = 1;(必须初始化)

  • 接口中属性的访问形式:接口名.属性名

  • 一个接口不能继承其他的类,但是可以继承多个别的接口

    • interface A extends B,C{}
  • 接口的修饰符只能是public 和默认,这点和类的修饰符是一样的

例题

interface A{
    int a =23;
}
class B implements A{
    
}


//在main中

B b = new B();
//b.a -----> 23
//A.a -----> 23
//B.a -----> 23

接口与继承类

小结:当之类继承了父类,就自动的拥有父类的功能。如果子类需要扩展功能,可以通过实现接口的方式扩展。

可以理解为 实现接口 是对java 单继承机制的一种补充

    //体会接口对于单继承机制的补充作用
    public class data01 {
        public static void main(String[] args) {
            LittleMonkey littleMonkey = new LittleMonkey(12, "大王");
            littleMonkey.swim();
            littleMonkey.play();
        }
    }
    
    interface Fish{
        void swim();
    }
    
    class Monkey{
        int age;
        String name;
    
        public Monkey(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        public void play(){
            System.out.println("Monkey played!");
        }
    }
    
    class LittleMonkey extends Monkey implements Fish{
        public LittleMonkey(int age, String name) {
            super(age, name);
        }
        public void swim(){
            System.out.println("LittleMonkey  can swim!");
        }
    }

继承的价值主要在于:解决代码的复用性和可维护性。

接口的价值主要在于:设计,设计好各种规范(方法),让其他类去实现这些方法,更加灵活

接口比继承更加灵活,继承是满足 is - a 的关系,而接口只满足 like - a 的关系

接口在一定程度上实现代码的解耦【接口的规范性+动态绑定】…后面会提及

接口的多态

  • 多态参数
//多态参数的实现

public class data01 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Camera camera = new Camera();
        Tool.tool(camera);
        Tool.tool(phone);

    }
}

interface USB{
    v}oid open();
    void close();
}

class Phone implements USB{
    @Override
    public void open() {
        System.out.println("手机连上了USB");
    }

    @Override
    public void close() {
        System.out.println("手机连接断开");
    }
}

class Camera implements USB{
    @Override
    public void open() {
        System.out.println("相机连接");
    }

    @Override
    public void close() {
        System.out.println("相机断开");
    }
}

class Tool{
    public static void tool(USB usb){
        usb.open();
        usb.close();
    }
}
//数组存放也可以
  • 多态传递

你可能感兴趣的:(Javase,学习历程,java,学习,开发语言)