JavaSE-入门2

一、static关键字
  • static是静态的意思,可以修饰成员变量和成员方法;

  • static修饰的成员变量表示该变量只在内存中只存储一份,可以共享访问与修改;

1.静态成员变量
  • static修饰的成员变量 —> 静态成员变量 (没有static的成员变量,为实例成员变量)
  • 访问方式一般是 类名.静态变量

image-20240114152939266

2.静态成员方法

成员方法的分类

  • 静态成员方法(有static修饰,归属于类),建议使用类访问,也可以使用对象访问,执行公用功能
  • 实例成员方法(无static修饰,归属于对象),只能通过对象触发访问,表示对象自己的行为

image-20240114153447390

3.static工具类

工具类

  • 内部都是一些静态方法,每个方法完成一个功能
  • 一次编写,处处可用,提高代码的重用性

工具类的要求

  • 建议工具类的构造器私有化
  • 工具类不需要创建对象
4.代码块

image-20240114154807089

/**
    1.顶一个静态集合,这样的集合只加载一次。
      因为房间内只需要一副牌
 */
public static ArrayList<String> cards = new ArrayList<>();

/**
    2.程序真正运行main方法前,将54张牌放进去,个数确定好!
 */
static {
    //3.正式做牌
    //a.四种花色的制作
    String[] number = new String[]{"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
    String[] colors = {"♥","♠","♦","♣"};

    for (int i = 0; i < number.length; i++) {
        for (int j = 0; j < colors.length; j++) {
            String card = number[i]+colors[j]; // 形如:2♥
            cards.add(card);
        }
    }
    //b.大小王
    cards.add("大🃏");
    cards.add("小🃏");
}

public static void main(String[] args) {
    //输出牌
    System.out.println("新牌:"+cards);
}
5.设计模式之创建型

单例模式(对象地址值唯一)

单例模式有以下特点:

  • 1单例类只能有一个实例;
  • 2单例类必须自己创建自己的唯一实例;
  • 3单例类必须给所有其他对象提供这一实例。
5.1懒汉单例

真正需要该对象的时候,才去创建一个对象

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    //1.构造器私有化
    private Singleton() {}
    /**
         2.定义存储一个静态成员变量 的 对象
           只加载一次,只有一份
           注意:!!!最好,进行私有化,可以避免给别人挖坑
     */
    private static Singleton single;
    // 3.仅提供一个方法,对外返回同一个对象
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}
//获取对象
SingleInstance instance2 = SingleInstance.getInstance();
SingleInstance instance21 = SingleInstance.getInstance();
//比较地址值
System.out.println(instance2 == instance21); //true
5.2饿汉单例

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变

//饿汉式单例类.在类初始化时,已经自行实例化 
public class Singleton {
	//私有化构造器
    private Singleton() {}
    //加载类时,耗时构造完成
    private static final Singleton single = new Singleton();
    //静态工厂方法 
    public static Singleton getInstance() {
        return single;
    }
}

饿汉式和懒汉式区别:

(1)初始化时机与首次调用:

  • 饿汉式是在类加载时,就将单例初始化完成,保证获取实例的时候,单例是已经存在的了。所以在第一次调用时速度也会更快,因为其资源已经初始化完成。
  • 懒汉式会延迟加载,只有在首次调用时才会实例化单例,如果初始化所需要的工作比较多,那么首次访问性能上会有些延迟,不过之后就和饿汉式一样了。

(2)线程安全方面:饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,懒汉式本身是非线程安全的,需要通过额外的机制保证线程安全

5.3登记式单例

登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。

/类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Singleton3 {
    private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
    static{
        Singleton3 single = new Singleton3();
        map.put(single.getClass().getName(), single);
    }
    //保护的默认构造子
    protected Singleton3(){}
    //静态工厂方法,返还此类惟一的实例
    public static Singleton3 getInstance(String name) {
        if(name == null) {
            name = Singleton3.class.getName();
            System.out.println("name == null"+"--->name="+name);
        }
        if(map.get(name) == null) {
            try {
                //反射构造实例对象
                map.put(name, (Singleton3) Class.forName(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return map.get(name);
    }
    //定义一个成员方法
    public String getSingleInfo() {
        return "Hello, I am RegSingleton.";
    }
    public static void main(String[] args) {
        Singleton3 single3 = Singleton3.getInstance(null);
        System.out.println(single3.getSingleInfo());
    }
}
二、继承

继承是什么?好处?

  • 继承就是允许使用extends关键字,建立两个类之间的父子关系
  • 提高代码复用性,减少代码冗余,增强类的扩展功能

格式?

子类extends父类

1.子类内存原理

image-20240114163752780

2.继承的特点?
  • 子类继承父类,子类可以得到父类的属性与行为,不能继承父类的构造器
  • 单继承模式,一个类只能继承一个父类,不支持多继承,但是允许多层继承
  • Java中所有的类都是Object类的子类

继承后的特点?

  • 在子类方法中,访问成员(成员变量,成员方法)满足就近原则,子类中没有找到,再从父类中找,找不到就报错
  • 如果子父类中出现了重名的成员,此时如何访问父类成员? super.父类成员(变量/方法)
3.方法重写

重写:子类与父类中一摸一样的方法声明,重新实现方法,用于父类不满足子类需求时;

@Override重写注解 : 建议重写方法都加上@Override注解,可以在编译阶段会出现错误提示,优雅!!!

方法重写的要求?

  • 重写方法的名称,形参列表必须与父类完全一致;
  • 私有方法不能被重写;
  • 子类不能重写父类的静态方法;
  • 子类重写父类方法时,访问权限必须大于或等于父类(暂时了解 : 缺省<protected<public)
4.继承构造器的特点

子类继承父类后构造器的特点:

  • 子类的所有构造器默认先访问父类中的无参构造器,再执行自己
  • 子类初始化如果需要使用父类的数据,需要使用完成父类的初始化!
  • 子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化;
  • 如何调用父类构造器?子类默认super(),不写也存在;

注意:

  • super调用父类有参构造器的作用:初始化父类的数据
  • 如果父类没有无参构造器,只有有参构造器,会报错!因为子类默认调用父类的无参构造
  • 子类构造器中通过书写super(…),手动调用父类的有参构造器;
5.this和super

image-20240114172902499

this(…)和super(…)都只能放在构造器的第一行,所以不能共存在同一个构造器中;

三、基础认识
1.包

同一个包下,不能定义相同的类名的类

导包

  • 相同包下的类可以直接访问,不同包下的类必须导包,格式 import 包名.类名
  • 加入一个类中需要很多的不同类,而这两个类的名称是一致的,则默认导入一个类,另一个类需要带包名访问
2.权限修饰符
  • 权限修饰符:是用于控制一个成员能够被访问的范围
  • 可以修饰成员变量、方法、构造器、内部类,不同权限修饰符修饰的成员能够访问的范围将收到限制

作用范围由小到大(private > 缺省 > protected > public)

修饰符同一个类中同一个包中其他类不同包下的子类不同包下的无关类
private
缺省
protected
public
3.final关键字

final作用:

  • final关键字是最终的意思,可以修饰(类、方法、变量)
  • 修饰类:表明该类是最终类,不可被继承
  • 修饰方法:表明该方法是最终方法,不可被重写
  • 修改变量:表明该变量第一次赋值后,不能再次被赋值(有且仅能赋值一次)

final修饰变量的注意:

  • 修饰基本类型变量,变量的数据值不可变;
  • 修饰引用类型变量,变脸的地址值不可变,但是地址指向的对象内容可以发生变化;
final Teacher teacher = new Teacher("万老师");
System.out.println(teacher);//Teacher{name='万老师'}
teacher.setName("王老师");
System.out.println(teacher);//Teacher{name='王老师'}
4.常量
  • 常量是使用public static final修饰的成员变量,必须有赋值,且不可修改

  • 常量可以用于做系统的配置信息,方便程序的维护,同时提高可读性

命名规范:英文单词大写,单词之间使用下划线连接

常量的执行原理:

  • 在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量"…";
  • 好处是,让使用常量的程序的执行性能与直接使用字面量一样
5.枚举
enum Season{
	//常量有 spring, summer, autumn,winter,系统会自动添加 public static final修饰
    spring,summer,autumn,winter;
} 
api描述
Enum.values()返回枚举类中的值
Enum.ordinal()可以找到每个枚举常量的索引,就像数组索引一样
Enum.valueOf()返回指定字符串值的枚举常量
public static void main(String[] args) {
//      1迭代季节values
        for (Season season : Season.values()) {
//          2ordinal可以找到每个枚举常量的索引,就像数组索引一样。
            System.out.println(season+"  索引为  "+season.ordinal());
        }
        //3valueOf
        System.out.println(Season.valueOf("summer"));
}

枚举的特征

  • 枚举类是继承了枚举类型:java.long.Enum
  • 枚举都是最终类,不可以被继承
  • 枚举的构造器都是私有的,对外不能创建对象
  • 枚举类的第一行默认都是罗列枚举对象的名称
  • 枚举类相当于是多例模式
四、oop进阶认识
1.抽象类

不完全设计类

  • 抽象类abstract,可以修饰类,成员方法;
  • abstract修饰类,这个类就是抽象类;修改方法,这个方法就是抽象方法;

格式

修饰符 abstract class 类名 { //抽象类

​ //抽象方法 , 不实现(没有大括号)

​ 修饰符 abstract 返回值类型 方法名(形参列表);

}

public abstract class Animal {
    //了解抽象类(父类),抽象方法并不实现(没有大括号)
    /**
        抽象方法
     */
    public abstract void run();
}    

注意:

  • 抽象方法只有方法签名,不能声明方法体;
  • 一个类中如果定义抽象方法,则该类必须声明为抽象类;
  • 一个类如果继承了抽象类,那么这个类必须重写全部的抽象方法;

使用场景:

  • 抽象类可以理解成不完整的设计图,一般作为父类,让子类 继承

  • 当父类知道子类一定要完成的某些行为,但每个子类的实现方式又不同,于是父类可把该行为定义为抽象行为,具体实现交由不同子类分别实现,同时父类声明为抽象类;

特征和注意事项:

  • 类有的成员(成员变量、方法、构造器)抽象类都具备
  • 抽象类中不一定有抽象方法,但有抽象方法一定是抽象类
  • 一个类继承了抽象类,必须重写全部的抽象类,否则该类应该定义为抽象类
  • 不能用abstract修饰变量、代码块、构造器
  • 最重要的特征:得到了抽象方法,失去了 new 对象的能力!!!(有得有失)

final和abstract的关系

  • 互斥关系
  • abstract定义为抽象类作为模板让子类继承,final定义的类是不可修改的,不能被继承
  • 抽象方法定义通用功能让子类重写,final定义的方法子类不能重写

1.2模板方法模式

(1)抽象类/抽象模板(Abstract Class)

​ 抽象模板类,负责给出一个算法的轮廓和骨架。
​ 它由一个模板方法和若干个基本方法构成。这些方法的定义如下:

  • 模板方法:定义了一套算法的骨架,按某种顺序调用其包含的基本方法。
  • 基本方法:是算法骨架/流程的某些步骤进行具体实现,包含以下几种类型,
    • 抽象方法:在抽象类中声明,由具体子类实现。
    • 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
    • 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

(2)具体子类/具体实现(Concrete Class)

具体实现类,实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

public abstract class AbstractCook {
	//模板使用final不可重写
    public final void doCook(){
        openFire();
        cooking();
        closedFire();
    }
    //嵌入的抽象方法
    protected abstract void cooking();

    protected void openFire() {
        System.out.println("点火,开始做菜了");
    }
    protected void closedFire() {
        System.out.println("关火,菜出锅了");
    }
}   
2.接口

格式

public interface 接口名{

​ //常量

​ //抽象方法 省去修饰符和abstract

}

JDK8之前,接口中只能是抽象方法和常量,没有其他成分

规范性

/**
    声明一个接口:体现一种规范,规范一定是公开的
 */
public interface InterfaceDemo {
    //目标:接口中成分的特点:  JDK 8.0之前接口只能由抽象方法和常量
    //1.常量
    //注意:规范! 默认是都是公开的 public,代码层面public static final可以省略不写
//    public static final String USER_NAME = "笑哈哈";
    String USER_NAME = "小白马";

    //2.抽象方法
    //注意:规范! 默认是公开的 public,代码层面public abstract 可以省略不写
	//public abstract void run();
    void run();
}

接口的用法:

  • 接口是被类实现的implements的,实现接口的类称为实现类。实现类可以理解为所谓的子类。

    • 格式 :

      ​ 修饰符 class 实现类 implements 接口1 , 接口2 , 接口3, … {

      ​ }

      ​ 实现的关键字 : implements , 多实现

  • 从上面可以看出,类可以实现多个接口

  • 一个类实现接口,必须重写全部的抽象方法,否则这个类需要定义为抽象类;

基本小结

  • 类和类之间的关系:单继承
  • 类和接口之间的关系:多实现
  • 接口和接口之间的关系:多继承,一个接口可以继承多个接口

JDK对接口的拓展(允许有实现方法的存在!!!)

  • JDK8后的新增哪些方法?
    • 默认方法:default修饰,实现类对象可调用;
    • 静态方法:static修饰,必须用当前接口名调用;
    • 私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用;
3.多态

同一件事情,发生在不同对象身上,就会产生不同的结果。

在java中要实现多态,必须要满足如下几个条件,缺一不可:

  • 1.必须在继承体系下
  • 2.子类必须要对父类中方法进行重写
  • 3.通过父类的引用调用重写的方法

同一类型(父类,接口),执行子类重写行为(同一个行为),不同表现

范围 小 --> 大 ;强制类型转变 大 --> 小

注意:地址的传递!!!!

多态的常见形式: 向上转型 自动类型转换

  • 父类类型 对象名称 = new 子类构造器

  • 接口 对象名称 = new 实现类构造器

编译先看父类是否该方法,运行则调用子类重写方法;

一般,父类对象只能使用与子类共有的功能,不能使用子类独有的;

向上转型的使用:

  • 直接赋值,这是最常见的向上转型

  • 将方法形参声明为父类类型,实际传入子类对象

  • 方法返回值为父类类型,实际返回子类对象

  • 构造器中调用父类方法

    public Cat(String name, int age) {
            super(age); // 调用父类构造函数
            this.name = name;
    }
    

解决不能访问子类独有方法的问题:强制类型转换,向下转型

子类类型 引用名 = (子类类型) 父类构造器

Animal a2 = new Tortoise();
//强制类型转换,编译阶段不会报错(注意:有继承或实现关系,编译阶段可以强制转换,没有毛病)
//运行时可以出错 , ClassCastException , 使用instanceof 进行匹配
Dog d1 = (Dog) a2;

解决

public static void sport(Animal a){
    //instanceof 进行匹配
    if(a instanceof Dog){
        Dog d = (Dog) a;
        d.lookDoor();
    }else if(a instanceof Tortoise){
        Tortoise t = (Tortoise) a;
        t.layEgg();
    }
}
4.内部类

image-20240114221240588

4.1静态内部类

image-20240114221549644

静态内部类的使用场景、特点与访问总结:

  • 如果一个类中包含了一个完整的成分,如汽车类中的发动机类
  • 特点、使用与普通类是一样的,类有的成分它都有,只是位置在别人类内部
  • 可以直接访问外部类的静态成员,不能直接访问外部类的实例成员(变量和方法)
  • 开发中实际用的比较少
4.2成员内部类

先创建外部类对象,才能创建内部类对象

特点:

  • 创建格式:Outer.Inter in = new Outer构造器 . new Inter构造器

  • 可以直接访问外部类的静态成员,实例方法中可以直接访问外部类的实例成员;

  • 无static修饰,属于外部类的对象

  • JDK16之前,成员内部类不能定义静态成员,JDK16开始也可以定义静态成员

成员内部类访问外部类对象,格式: 外部类名.this.方法名

4.3局部内部类

语法格式

[修饰符] class 外部类{
    [修饰符] 返回值类型  方法名([形参列表]){
            [final/abstract] class 内部类{
       		 }
    }    
}

局部内部类的特点:

  1. 定义在类的某个方法里,而不是直接定义在类里

  2. 局部内部类前面不能有权限修饰符

  3. 局部内部类里不能使用static声明变量

  4. 局部内部类访问外部类的静态成员

  5. 如果这个局部内部类所在的方法是静态的,它无法访问外部类的非静态成员

  6. 局部内部类 可以访问外部方法 的局部变量 ,但 这个局部变量必须要非final修饰。JDK8以后,final可以省略

实现

/**
 * 局部内部类实现
 */
class Outer {
    int age = 19;
    static int m = 10;

    public void test() {
        // final String y = "good";
        String y = "good";  // JDK8 以后,final可以省略
        class Inner {  // 定义在外部类的某个方法里
            // static int a = 10; 不能定义静态变量!  
            private  void demo() {
                System.out.println(age);
                // 不能修改外部类成员方法内的局部变量
                // y = 'yes';
                // 只能访问被 final 修饰的外部方法的局部变量
                // JDK8 以后,如果外部函数的局部变量没有加 final,编译器会自动加 final
                System.out.println(y);
            }
        }
        Inner inner = new Inner();
        inner.demo();
    }
}

public class Test1{
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.test();
    }
}
4.4匿名内部类

用来创建一个 接口抽象类对象

格式

new 父类名 / 接口名(){   
    // 方法重写
    @Override 
    public void method() {
        // 执行语句
    }
};

匿名内部类特点:

  • 匿名内部类就是一种特殊的局部内部类,只不过没有名称而已,基本特点和局部内部类一致

  • 匿名内部类不能有构造器,匿名内部类没有类名,肯定无法声明构造器

  • 匿名内部类的前提是,这个内部类必须要继承自一个父类或者父接口

  • 匿名内部类是接口的一种常见简化写法,也是我们开发中最常使用的一种内部类。它的本质是一个实现类父类或者父类接口具体方法的一个匿名对象。

//匿名内部类 作为一个方法的参数使用
public class AnonymousTest {
 	//成员方法
    public int calculate(int a,int b,Calculator calculator){
        return calculator.doCalculator(a, b);
    }
    
    //main
    public static void main(String[] args) {
        AnonymousTest test = new AnonymousTest();
 		//匿名内部类  接口对象
        Calculator c = new Calculator() {
            @Override
            public int doCalculator(int a, int b) {
                return a+b;
            }
        };
        
        int x = test.calculate(1,9,c);
        //等价
        int y = test.calculate(1, 9, new Calculator() {
            @Override
            public int doCalculator(int a, int b) {
                return a+b;
            }
        });
 
        System.out.println(x);
    }
}
 
interface Calculator{
    int doCalculator(int a,int b);
}
  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值