Java Skills

learn it again

基础知识

介绍

javaSE EE ME

Java SE:Standard Edition

Java EE:Enterprise Edition

Java ME:Micro Edition

┌───────────────────────────┐
│Java EE │
│ ┌────────────────────┐ │
│ │Java SE │ │
│ │ ┌─────────────┐ │ │
│ │ │ Java ME │ │ │
│ │ └─────────────┘ │ │
│ └────────────────────┘ │
└───────────────────────────┘

JDK JRE

JDK:Java Development Kit
JRE:Java Runtime Environment ┌─ ┌──────────────────────────────────┐
│ │ Compiler, debugger, etc. │
│ └──────────────────────────────────┘
JDK ┌─ ┌──────────────────────────────────┐
│ │ │ │
│ JRE │ JVM + Runtime Library │
│ │ │ │
└─ └─ └──────────────────────────────────┘
┌───────┐┌───────┐┌───────┐┌───────┐
│Windows││ Linux ││ macOS ││others │
└───────┘└───────┘└───────┘└───────┘

JRE是虚拟机,运行游戏就装JRE,运行Java字节码
JDK包括JRE和开发工具,提供了编译器、调试器等

java:这个可执行程序其实就是JVM,运行Java程序,就是启动JVM,然后让JVM执行指定的编译后的代码;
javac:这是Java的编译器,它用于把Java源码文件(以.java后缀结尾)编译为Java字节码文件(以.class后缀结尾);
jar:用于把一组.class文件打包成一个.jar文件,便于发布;
javadoc:用于从Java源码中自动提取注释并生成文档;
jdb:Java调试器,用于开发阶段的运行调试。

程序基础

命名规范

public static void main(String[] args)

类名要求:GoodMorning

  • 类名必须以英文字母开头,后接字母,数字和下划线的组合
  • 习惯以大写字母开头

方法名: goodMorning

  • 首字母小写
  • 之后每个单词首字母大写

变量和数据类型

计算机内存的最小存储单元是字节(byte),一个字节就是一个8位二进制数,即8个bit。它的二进制表示范围从00000000~11111111,换算成十进制是0~255,换算成十六进制是00~ff。

整型

最高位的bit表示符号位(0表示正数,1表示负数)

byte(1位):-128 ~ 127
short(2位): -32768 ~ 32767 int(4位): -2147483648 ~ 2147483647 long(8位): -9223372036854775808 ~ 9223372036854775807

浮点型

对于float类型,需要加上f后缀

float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38  
double d = 1.79e308;  

float(4位):可最大表示3.4x1038
double(8位):可最大表示1.79x10308

布尔型

Java语言对布尔类型的存储并没有做规定,因为理论上存储布尔类型只需要1 bit,但是通常JVM内部会把boolean表示为4字节整数。

boolean b1 = true;
boolean b2 = false;
boolean isGreater = 5 > 3; // 计算结果为true

字符类型(2位)

注意char类型使用单引号’,且仅有一个字符

char a = 'A';
char zh = '中';

常量

定义变量的时候,如果加上final修饰符,这个变量就变成了常量:

final double PI = 3.14; // PI是一个常量
常量在定义时进行初始化后就不可再次赋值,再次赋值会导致编译错误
根据习惯,常量名通常全部大写

var关键字

使用var定义变量,仅仅是少写了变量类型而已

var sb = new StringBuilder();
编译完会变成
StringBuilder sb = new StringBuilder();

整数运算

移位运算

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n << 1;  // 00000000 00000000 00000000 00001110 = 14
int b = n << 2;  // 00000000 00000000 00000000 00011100 = 28
左移实际上就是不断地×2,右移实际上就是不断地÷2(右移补符号位)

强制类型转换

int i = 12345;
short s = (short) i; // 12345

布尔运算

三元运算符

int x = n >= 0 ? n : -n;
上述语句的意思是,判断n >= 0是否成立,如果为true,则返回n,否则返回-n。这实际上是一个求绝对值的表达式。

字符和字符串

char 单引号’’ string 双引号i "”

String是引用类型,本质是class,所以有不可变特性:每次重新赋值相当于开辟新的储存空间,并将命名的那个指针指过去

Java的编译器对字符串做了特殊照顾,可以使用+连接任意字符串和其他数据类型

\ 转义符号

  • " 表示字符”
  • ' 表示字符’
  • \\ 表示字符\
  • \n 表示换行符
  • \r 表示回车符
  • \t 表示Tab
  • \u#### 表示一个Unicode编码的字符

int[] ns = new int[5];

与普通数组(比如整形)不一样,字符串数组本质使用的是指针指向不同字符串

流程控制

输入和输出

println是print line的缩写,表示输出并换行。因此,如果输出后不想换行,可以用print()

格式化输出

使用System.out.printf(),通过使用占位符%?,printf()可以把后面的参数格式化成指定格式

%d 格式化输出整数
%x 格式化输出十六进制整数
%f 格式化输出浮点数
%e 格式化输出科学计数法表示的浮点数
%s 格式化字符串

double d = 3.1415926;  
System.out.printf("%.2f\n", d); // 显示两位小数3.14
System.out.printf("%.4f\n", d); // 显示4位小数3.1416
double d = 3.1415926;

输入

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建Scanner对象
        System.out.print("Input your name: "); // 打印提示
        String name = scanner.nextLine(); // 读取一行输入并获取字符串
        System.out.print("Input your age: "); // 打印提示
        int age = scanner.nextInt(); // 读取一行输入并获取整数
        System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
    }
}

if

判断引用类型相等

在Java中,判断值类型的变量是否相等,可以使用==运算符。但是,判断引用类型的变量是否相等,==表示“引用是否相等”,或者说,是否指向同一个对象

判断变量内容相等

要判断引用类型的变量内容是否相等,必须使用equals()方法
执行语句s1.equals(s2)时,如果变量s1为null,会报NullPointerException

==和equal
java中有两种数据类型 基本数据类型和复合数据类型 基本类型包括:short int byte long char 等 基本数据类型可以直接比较
复合数据类型:当时用==比较的时候,比较的是他们的的内存地址 Object是所有类的基类,他其中有equal方法,也是比较的内存的地址

switch

int option = 2;
switch (option) {
case 1:
    System.out.println("Selected 1");
case 2:
    System.out.println("Selected 2");
case 3:
    System.out.println("Selected 3");
default:
    System.out.println("Not selected");
}

for&for-each

for each与python中的for用处基本相同

int[] ns = { 1, 4, 9, 16, 25 };
for (int n : ns) {
    System.out.println(n);
}

toString

通过toString打印,但是效果速度适用面不如强制类型转换String()

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 1, 2, 3, 5, 8 };
        System.out.println(Arrays.toString(ns));
    }
}

数组排序sort

import java.util.Arrays;

int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
Arrays.sort(ns);

String[] args

程序固定第一行
public static void main(String[] args)

其中 String[] args 可以接受一个命令行参数,它是一个String[]数组

$ java Main -t -l -xxx

意思就是可以在执行程序的时候输入一些参数,有点像做机器学习毕设时,在xxx.py后面加入了各种参数=多少的设定

OOP 面向对象

面向对象基础

private

作用域在实例中

this

  • 它始终指向当前实例,通过this.field就可以访问当前实例的字段
  • 如果没有命名冲突,可以省略this

可变参数

可变参数用类型...定义,相当于数组 什么时候用?在不确定方法需要处理的对象的数量时可以使用可变长参数,会使得方法调用更简单,无需手动创建数组 new T[]{…}

构造方法

多构造方法:this

集合 collection

List:一种有序列表的集合, Set:一种保证没有重复元素的集合 Map:一种通过键值(key-value)查找的映射表集合

list

List是最基础的一种集合:它是一种有序链表 boolean contains(Object o)方法来判断List是否包含某个指定元素 int indexOf(Object o)方法可以返回某个元素的索引,如果元素不存在,就返回-1

Map

boolean containsKey(K key) 遍历HasMap时,key是无序的,也不是存入的顺序!LikedHashMap额外保证了Map的遍历顺序与put顺序一致的有序性

HashMap

要遍历key可以使用for each循环遍历Map实例的keySet()方法返回的Set集合,它包含不重复的key的集合

for (String key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println(key + " = " + value);
}
同时遍历key和value可以使用for each循环遍历Map对象的entrySet()集合,它包含每一个key-value映射

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println(key + " = " + value);
}

TreeMap

TreeMap等所有SortedMap保证遍历时以Key的名称顺序来进行排序 底层使用红黑树来实现的
如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法Comparator(或者直接借助Integer.compare(int, int)也可以返回正确的比较结果)

 Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {
    public int compare(Student p1, Student p2) {
        if (p1.score == p2.score) {
        return 0;
        }
        return p1.score > p2.score ? -1 : 1;
    }
});

三种Map的使用场景

  • TreeMap:需要基于排序的统计功能: 由于TreeMap是基于红黑树的实现的排序Map,对于增删改查以及统计的时间复杂度都控制在O(logn)的级别上,相对于HashMap和LikedHashMap的统计操作的(最大的key,最小的key,大于某一个key的所有Entry等等)时间复杂度O(n)具有较高时间效率。

  • HashMap:需要快速增删改查的存储功能: 相对于HashMap和LikedHashMap 这些 hash表的时间复杂度O(1)(不考虑冲突情况),TreeMap的增删改查的时间复杂度为O(logn)就显得效率较低。

  • LikedHashMap:需要快速增删改查而且需要保证遍历和插入顺序一致的存储功能:
    相对于HashMap和LikedHashMap 这些 hash表的时间复杂度O(1)(不考虑冲突情况),TreeMap的增删改查的时间复杂度为O(logn)就显得效率较低。但是HashMap并不保证任何顺序性。LikedHashMap额外保证了Map的遍历顺序与put顺序一致的有序性。


Set

Set实际上相当于只存储key、不存储value的Map。我们经常用Set用于去除重复元素

队列Queue

队列Queue实现了一个先进先出(FIFO)的数据结构:

  • 通过add()/offer()方法将元素添加到队尾;
  • 通过remove()/poll()从队首获取元素并删除;
  • 通过element()/peek()从队首获取元素但不删除。

要避免把null添加到队列。