Java学习笔记


本文章是我的 Java 学习笔记,虽然本科时学过 Java ,但是学完就基本没用过了,导致现在又得重新学习了,所以学东西一定要学好学精,不能什么都学个大概。写本文的原因有两个,一来觉得学东西的时候记录下来学习效率会比较高,二来记忆力下降明显,方便自己以后复习吧!

类变量(静态变量)

类变量简介

类变量(又叫静态变量)是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

类变量内存布局

  • jdk8 及以前版本,放在静态域;

  • jdk8 以后版本,放在堆中,当你的类加载的时候会在堆中生成一个类的 class 对象,静态变量就在 class 对象尾部。

类变量特点

  • 类变量是同一个类所有对象实例共享的
  • 类变量,在类加载的时候就生成了
    • (即类加载的时候就会初始化类变量,即使没有创建类对象实例也可通过类名访问)
  • 类变量的生命周期是随类的加载开始,随着类的消亡而销毁。

类变量的定义

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

类变量的访问

  • 类名.类变量名【推荐使用】
  • 对象名.类变量名

类变量使用场景

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

类变量与普通变量

  • 类变量是该类的所有对象共享的,
  • 实例变量(普通变量/类成员变量/非静态变量)是每个对象独享的。

代码理解类变量

public class ChildGame {
    public static void main(String[] args) {
        //普通方法需定义一个变量 count, 统计有多少小孩加入了游戏
        //int count = 0;
        Child child1 = new Child("白骨精");
        child1.join();
        //count++;
        child1.count++;
        Child child2 = new Child("狐狸精");
        child2.join();
        //count++;
        child2.count++;
        Child child3 = new Child("老鼠精");
        child3.join();
        //count++;
        child3.count++;

        //类变量,可以通过类名来访问,也可通过对象名访问
        System.out.println("共有" + Child.count + " 小孩加入了游戏...");
        System.out.println("child1.count=" + child1.count);//3
        System.out.println("child2.count=" + child2.count);//3
        System.out.println("child3.count=" + child3.count);//3
    }
}

class Child {
    private String name;
    public static int count = 0;  //该变量最大的特点就是会被 Child 类的所有的对象实例共享
    public Child(String name) {
        this.name = name;
    }
    public void join() {
        System.out.println(name + " 加入了游戏..");
    }
}

类方法(静态方法)

类方法,无需创建类的对象即可对其进行访问

类方法定义

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

类方法访问

  • 类名.类方法名【推荐使用】
  • 对象名.类方法名

类方法使用场景

  • 当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
  • 比如工具类中的方法 utils, Math类、Arrays类、Collections集合类
  • 在实际开发中,往往将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用,比如打印一维数组,冒泡排序等等

类方法与普通方法

  • 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:类方法中无 this 的参数,普通方法中隐含着 this 的参数。
  • 类方法可以通过类名或对象名调用,而普通方法只能通过对象名调用。
  • 类方法中不允许使用和对象有关的关键字,比如 thissuper;普通方法可以。(因为当用类名.类方法名调用的时候,this和super指示不明)
  • 类方法中,只能访问静态变量或静态方法;而普通方法既可以访问普通变量(方法),也可以访问静态变量(方法)。

代码理解类方法

package com.jwt.static_;

public class StaticMethod {
    public static void main(String[] args) {
        //创建两个学生交学费
        Stu tom = new Stu("Tom");
        tom.payFee(100);
        Stu mary = new Stu("mary");
        mary.payFee(200);
        Stu.showFee();
    }
}

class Stu{
    private String name;
    private static  double fee = 0;//静态变量累积学费
    public Stu(String name) {
        this.name = name;
    }
    public static void payFee(double fee){//静态方法可访问静态变量
        Stu.fee += fee;
    }
    public static void showFee(){
        System.out.println("总学费:" + Stu.fee);
    }
}

main方法

深入理解main方法

main 方法的形式: public static void main(String[] args){}

  • public:main 方法是 JVM 调用的,该方法的访问权限必须是 public;

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

  • args:该方法接收 String 类型的数组参数,该数组中保存执行 Java 命令时传递给所运行的类的参数

特别注意

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

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

IDEA 中给main传参数

第一步 第二步

代码块

简介

代码块又称为 初始化块,属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过 { } 包围起来,但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时或创建对象时隐式调用。

代码块语法

[修饰符]{
代码
};

说明:

  • 修饰符可选,要写的话,也只能写 static
  • 代码块分为两类,使用 static 修饰的叫静态代码块,没有 static 修饰的,叫普通代码块
  • 块中代码可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
  • 分号,可以写上,也可以省略

代码块的好处

首先看下面代码,三个构造器都有相同的语句,这样代码看起来比较冗余,如何简化代码呢?

public class CodeBlock01 {
    public static void main(String[] args) {
        Movie movie = new Movie("你好,李焕英");
        System.out.println("===============");
        Movie movie2 = new Movie("唐探3", 100, "陈思诚");
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    //3个构造器-》重载
    public Movie(String name) {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
        System.out.println("Movie(String name) 被调用...");
        this.name = name;
    }

    public Movie(String name, double price) {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
        System.out.println("Movie(String name, double price, String director) 被调用...");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

这时我们可以把相同的语句,放入到一个代码块中,这样当我们不管调用哪个构造器创建对象,都会先调用代码块的内容,代码块调用的顺序优先于构造器

{
    System.out.println("电影屏幕打开...");
    System.out.println("广告开始...");
    System.out.println("电影正是开始...");
};

改进后代码:

public class CodeBlock01 {
    public static void main(String[] args) {
        Movie movie = new Movie("你好,李焕英");
        System.out.println("===============");
        Movie movie2 = new Movie("唐探3", 100, "陈思诚");
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    //代码块
    {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
    };
    //3个构造器-》重载
    public Movie(String name) {
        System.out.println("Movie(String name) 被调用...");
        this.name = name;
    }

    public Movie(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
        System.out.println("Movie(String name, double price, String director) 被调用...");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

总结

  • 代码块相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作。
  • 如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的复用性

重点

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

  • 类什么时候被加载

    • 创建对象实例时(new)
    • 创建子类对象实例,父类也会被加载
    • 使用类的静态成员时(静态方法,静态属性)
  • 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。

  • 如果只是使用类的静态成员时,普通代码块并不会执行。

  • 创建一个对象时,它们的调用顺序是:

    • ➀首先调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
    • ➁再调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
    • ➂最后调用构造方法。
  • 构造器的最前面其实隐含了 super() 和调用普通代码块。

  • 静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员

  • 创建一个子类对象时,在一个类调用顺序是:

    • ➀ 父类的静态代码块和静态属性初始化(优先级一样,按定义顺序执行)
    • ➁ 子类的静态代码块和静态属性初始化(优先级一样,按定义顺序执行)
    • ➂ 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
    • ➃ 父类的构造方法
    • ➄ 子类的普通代码块和普通属性初始化
    • ➅ 子类的构造方法

总结:
1——根据static代码块是在类加载时被调用,当要创建子类这个对象时,发现这个类需要一个父类,所以把父类的 .class 加载进来,故先是父类的静态代码块或静态属性初始化;
2——然后是加载子类的类信息,故是子类的静态代码块或静态属性初始化;
3——然后走进子类构造器的super语句,进入父类的构造器,先super(),然后调用父类普通代码块,故是父类的普通代码块或普通属性初始化;
4——然后父类构造器调用完毕,即是父类的构造方法;
5——然后回到子类的构造方法中隐含的调用普通代码块或普通属性的初始化;
6——然后完成子类的构造器,故最后是子类的构造方法。

单例模式

饿汉式

懒汉式

StringBuilder 类

StringBuilder 是一个可变的字符串类,String内容是不可变的,StringBuilder内容是可变的

创建Stringbuilder对象

StringBuilder strB = new StringBuilder();

1、append(String str)/append(Char c):字符串连接

System.out.println("StringBuilder:"+strB.append("ch").append("111").append('c'));
//return "StringBuilder:ch111c"

2、toString():把Stringbuilder转换为String输出

System.out.println("String:"+strB.toString());
//return "String:ch111c"

3、appendcodePoint(int cp):追加一个代码点,并将其转换为一个或两个代码单元并返回this

System.out.println("StringBuilder.appendCodePoint:"+strB.appendCodePoint(2));
//return "StringBuilder.appendCodePoint:ch111c"

4、setCharAt(int i, char c):将第 i 个代码单元设置为 c(可以理解为替换)

strB.setCharAt(2, 'd');
System.out.println("StringBuilder.setCharAt:" + strB);
//return "StringBuilder.setCharAt:chd11c"

5、insert(int offset, String str)/insert(int offset, Char c):在指定位置之前插入字符(串)

System.out.println("StringBuilder.insertString:"+ strB.insert(2, "LS"));
//return "StringBuilder.insertString:chLSd11c"
System.out.println("StringBuilder.insertChar:"+ strB.insert(2, 'L'));
//return "StringBuilder.insertChar:chLLSd11c"

6、delete(int startIndex,int endIndex):删除起始位置(含)到结尾位置(不含)之间的字符串

System.out.println("StringBuilder.delete:"+ strB.delete(2, 4));
//return "StringBuilder.delete:chSd11c"

包装类

Java 中的包装类提供了将原始数据类型转换为对象,以及将对象转换为原始数据类型的机制。

java.lang包的八个类在 java 中称为包装类。八个包装类的列表如下:

基本类型 包装类
int Integer
char Character
byte Byte
short Short
boolean Boolean
long Long
float Float
double Double

为什么需要包装类?

包装类是一个对象,基本类型不是。当需要一个适合像面向对象编程的类型时就需要包装类。当希望数据类型变得简单时就使用原始类型。原始类型不能为null,但包装类可以为null。包装类可用于实现多态性。

装箱和拆箱

。。。

总结:

包装类比较大小的时候有很多坑,比如: == 比较引用,Integer 类型只有在-128 到 127 的范围内,才会持有同一个引用,因此需要使用 equals() 代替 == 来比较值是否相等。equals 方法会先比较类型是否一致,不一致直接 false。

Java 数据结构

栈(Stack)

Stack 类是 Vector 类的一个子类,实现了一个后进先出(LIFO)的数据结构。

Stack 创建对象:

Stack<Integer> stack = new Stack<>();
Stack<Character> stack = new Stack<>();

Stack 方法:

序号 方法描述
1 boolean empty() 测试堆栈是否为空。
2 Object peek( ) 查看堆栈顶部的对象,但不从堆栈中移除它。
3 Object pop( ) 移除堆栈顶部的对象,并作为此函数的值返回该对象。
4 Object push(Object element) 把项压入堆栈顶部。
5 int search(Object element) 返回对象在堆栈中的位置,以 1 为基数。

Stack 测试:

import java.util.Stack;
public class test {
    public static void main(String[] args){
        //1.创建一个字符型的栈
        Stack<Character> stack = new Stack<>();
        System.out.println(stack);
        //2.测试栈是否为空
        System.out.println(stack.empty());
        //3.入栈
        stack.push('a');
        stack.push('b');
        stack.push('c');
        System.out.println(stack);
        //4.查看栈顶元素
        System.out.println(stack.peek());
        //5.出栈
        stack.pop();
        System.out.println(stack);
        //6.返回对象在栈中的位置
        System.out.println(stack.search('b'));
        System.out.println(stack.search('a'));
    }
}

/**
[]
true
[a, b, c]
c
[a, b]
1
2
**/

快捷键

创建构造函数:AIt + Inster

参考:

Java - 标签 - Wiiiimp - 博客园 (cnblogs.com)

❤️Sponsor

您的支持是我不断前进的动力,如果你觉得本文对你有帮助,你可以请我喝一杯冰可乐!嘻嘻🤭

支付宝支付 微信支付

文章作者: 简简
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 简简 !
评论-----昵称和邮箱必填,网址选填
 本篇
Java学习笔记 Java学习笔记
本文章是我的 Java 学习笔记,虽然本科时学过 Java ,但是学完就基本没用过了,导致现在又得重新学习了,所以学东西一定要学好学精,不能什么都学个大概。写本文的原因有两个,一来觉得学东西的时候记录下来学习效率会比较高,二来记忆力下降明显
2021-09-07
下一篇 
LeetCode 算法入门 LeetCode 算法入门
在数学和计算机科学之中,算法是一个被定义好的、计算机可施行之指示的有限步骤或次序,常用于计算、数据处理和自动推理。作为一个有效方法,算法被用于计算函数,它包含了一系列定义清晰的指令,并可于有限的时间及空间内清楚的表述出来。
2021-07-26
  目录