欢迎食用『主界面』~,这里是赵苦瓜的看板娘desu~
【点滴记录】Java的初步入门(更新中)
首页 > 点滴记录    作者:赵苦瓜   2022年3月1日 9:01 星期二   热度:366°   百度已收录  
时间:2022-3-1 9:01   热度:366° 

前言

Java的JDK的安装是直接用的IDEA自带的那个安装的,

然后学习的教程也是廖雪峰老师的教程。

Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)


Java常见三种版本:

Java SE:Standard Edition(标准版)

Java EE:Enterprise Edition(企业版,web开发)

Java ME:Micro Edition(移动端,如半智能手机)

三者的关系图

┌───────────────────────────┐
│Java EE                                                  │
│    ┌────────────────────┐       │
│    │Java SE                                   │       │
│    │    ┌─────────────┐        │      │
│    │    │   Java ME               │        │      │
│    │    └─────────────┘        │      │
│    └────────────────────┘       │
└───────────────────────────┘
JDK:Java Development Kit
JRE:Java Runtime Environment(Java虚拟机)


设置环境变量

JAVA_HOME 指向JDK的安装路径 比如:C:\Users\DELL\.jdks\openjdk-17.0.2

然后在PATH里面添加bin:%JAVA_HOME%\bin

添加成功后,就可以在cmd里面尝试一下了:

C:\Users\DELL>java -version
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)


Java的bin目录下也有很多东西,比如java就是JVM虚拟机,javac是Java的编译器,jar可以把class打包成jar,javadoc可以从Java源码中自动提取注释并生成文档,jdb可以用于开发阶段的调试。


第一个程序

hello world

public class Hello {
	public static void main(String[] args) {
		System.out.println("Hello World!");
	}
}
↑文件名必须与类名相同,即Hello.java


然后编译为class文件,之后就可以运行了。

一个java源码只能定义一个public 类型的class,且要与文件名一致。

PS F:\Java> javac .\Hello.java

PS F:\Java> java Hello
Hello World!


执行java虚拟机运行时,传入的是类名,而不是.class文件。Java虚拟机会自动寻找这个类名的class文件并执行。


Java 11 新增功能,虚拟机可以直接运行.java文件

PS F:\Java> java Hello.java
Hello World!



Java规定,某个类定义的public static void main(String[] args)是Java程序的固定入口方法,Java程序总是从main方法开始执行。


命名规则

类名:首字母大写,驼峰命名法。

方法名:首字母小写,驼峰命名法。


注释

// 单行注释

/*    */  多行注释

/**  */ 文档注释(如果有多行,通常每行以*开头)

生成文档的命令:javadoc xxx.java

javadoc -d doc -encoding utf-8 -charset UTF-8 HelloWorld.java
-d指定路径,encoding指定编码 charset指定字符集,这样可以防止中文乱码的问题。



public class HelloWorld {
    /**
     * 这是第一个java程序
     * @param args 喵
     */
    public static void main(String[] args) {
        System.out.println("HelloWorld");
        // 单行注释  
    /*
        多行注释
         */
    }
}


变量

Java中有两种变量类型,基本类型的变量和引用类型的变量。

变量必须先定义后使用。定义时可以赋初值。与C语言类似。

基本数据类型

整数类型:byte、short、int、long

浮点类型:float、double

字符类型:char

布尔类型:boolean


Java只定义了有符号的整型,最大范围如下:

byte:-128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
long: -9223372036854775808 ~ 9223372036854775807

float:3.4x1038

double:1.79x10308

boolean:true和false

char:ASCII码或者Unicode表示的单个字符,用单引号引起来。


Java中数字也可也加下划线方便人看,不影响数值。

byte a1 = 56;
        short a2 = -1256;
        int a3 = 114_514;  // 可以加下划线方便观看
        long a4 = 1_919_810L; // long类型需要在后面加L
        int a5 = 0b10010;  // 二进制以0b开头
        int a6 = 0x000000b; // 十六进制以0x开头
        int a7 = 0554;  // 八进制以0开头

        float f1 = 3.14f;  // float后面加f
        float f2 = 3.14e32f;  // 科学计数法表示3.14乘10的32次方
        double d1 = 1.79e308;
        double d2 = -1.79e308;
        double d3 = 4.9e-324;

        boolean b1 = true;
        boolean b2 = 5 > 2;
        int age = 12;
        boolean b3 = age>15;
        boolean bf = true;

        char c1 = 'A';  // 可以表示显示常规的ASCII字符,用单引号引起来(双引号是字符串类型,要区分)
        char c2 = '中';  // 也可以表示unicode字符
        System.out.println(c1);
        System.out.println(c2);


上述是基本类型,其他类型都是引用类型。

引用类型类似于C语言的指针。

String:字符串,用双引号引起来。

String s1 = "这是一句话。";
        System.out.println(s1);



常量

常量:在定义时加上final修饰符,就是定义常量。

final double PI = 3.1415926;  //常量定义后不可修改


var 自动推断变量类型

StringBuilder s2 = new StringBuilder();
        var s3 = new StringBuilder(); // 这样写的效果和上面相同。编译器可以自动推断简单变量。



变量作用域:

定义变量时要使用最小作用域原则,而且尽量不要重名。


数值运算

Java的数值运算基本与数学一致。

加+ 减- 乘* 除/ 括号() 除余%

简写运算符+= -= *= /=

++自增 --自减

整数相除永远会是整数。

除以0时编译不会报错,运行会报错。

计算超出范围不会报错,会导致溢出。


位运算

移位运算>>  <<  先转换成二进制再运算。首位表示符号。

无符号的右移>>>

        int a = 3; // 00000000 00000000 00000000 00000011
        int n1= a<<1; // 00000000 00000000 00000000 00000110
        // 首位表示符号0正1负
        // 负数向右移位首位不会变
        int n2 = -536870912;
        int n3 = n2 >> 1;  // 11110000 00000000 00000000 00000000 = -268435456
        int n4 = n2 >> 2;  // 11111000 00000000 00000000 00000000 = -134217728
        int n5 = n2 >> 28; // 11111111 11111111 11111111 11111110 = -2
        int n6 = n2 >> 29; // 11111111 11111111 11111111 11111111 = -1
        // 无符号的向右移位>>> 最高位移动之后会补0

对于bytes和short类型的数据移位,会先转换成int再移位。


与& 或| 非~ 异或^


Java运算的优先级:


()
! ~ ++ --
* / %
+ -
<< >> >>>
&
|
+= -= *= /=

记不住用括号。


类型转换

自动类型转换:运算时总是转换为范围更大的类型。

强制类型转换:前面加括号,括起来类型。

强制类型转换时,高位会被直接舍弃,得到错误结果。

short i2 = (short)a3;



浮点数运算由于二进制转换的问题常常不准确,会产生误差。

比较浮点数是否相等通常采用做差然后判断是否小于一个很小的数。

整数和浮点数运算时会自动转换为浮点数。

浮点数除以0之后不会报错,会返回特殊数值。

        double fl1 = 0.0/0; // NaN 不是数字
        double fl2 = 1.0/0; // Infinity 无穷
        double fl3 = -1.0/0; //-Infinity 负无穷

强制转换成整数时会丢弃小数部分。

如果要四舍五入可以先加上0.5再进行转换。

当整数不够时会转换为整数能表示的最大数值。



布尔运算


比较运算符:>,>=,<,<=,==,!=
与运算 &&
或运算 ||
非运算 !


短路运算


三元运算符 x?y:z  原理和c语言一致。


Java中字符都使用Unicode编码,将字符赋值给int即可查看对应的编码。

可以使用\uXXXX  十六进制 表示对应编码的字符


Java中可以用+符号连接任意字符串和其他数据类型,其他类型都会被转换成字符串。

Java13开始可以用三个双引号来引起来多行字符串(和Python类似)""" """

多行字符串前面共同的空格会被去掉,总是以最短的行首空格为基准。


字符串不可变,只是变了指针。

字符串可以赋值为null,即不指向任何字符串。和空字符串不一样。


数组类型

类型[] 变量名 这是Java的写法。当然也可以用C的写法  类型 变量名[]

比如int[] a = new int[5]  或者 int a[] = new int[5]

创建初始化时必须写new表示创建一个数组。


Java数组初始化时都有默认值,比如整型默认是0,浮点型0.0,布尔型false

数组一旦创建,长度就不可变。

可以用数组.lenth获取数组大小

        int[] a = new int[5];
        a[0] = 1;
        a[1] = 2;
        System.out.println("" + a[0] + a[1] + a[2]);   // 120
        System.out.println(a.length);  // 5


也可以在初始化时直接写好值,不写长度,会自动推断lenth。

        int[] b = new int[] {1,5,8,6,9,7,4,7};
        System.out.println(b.length);  // 8


甚至后面的new int[] 都可以省略,更加简化。


字符串数组

String[] names = {
                "喵", "旺"
        };
        System.out.print(names[0]);
        System.out.print(names[1]);



输出

println是printline的缩写,打印后会在末位打印一个换行符。

直接print是没有换行符的。

printf是格式化输出,可以把后面的内容转换成制定形式,于C语言类似。

%d 整数 %x 十六进制整数  %f 浮点数 %e 科学计数法的浮点数 %s 字符串

%% 转义表示%本身


输入

scanner方法:

导包import java.util.Scanner;

Java中的import必须放在源码的开头

Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        int age2 = scanner.nextInt();


创建Scanner对象,放入标准输入流,然后读入一行文本。

nextInt()可以自动把读入的文本转换为对应的数据类型,而不需要手动转换。



if判断

if(条件1){

    //条件1满足执行

else if (条件2) {

    //条件1不满足且条件2满足时执行

} else {

    //都不满足时执行

}


if语句块只有一行语句时,可以省略花括号。(但是不推荐省略花括号)


浮点数判断通常会有误差所以不靠谱,通常采用差值小于临界值来判断。Math.abs(x - 0.1) < 0.00001


Java中判断值类型的相等可以直接用==,但是引用类型不可以,就算值相同,==的结果也是false。

因为引用类型通常表示为不同的对象。此时应该用equals方法进行比较。

        String test1 = "Hello";
        String test2 = "Hell";
        test2 = test2 + "o";
        System.out.println(test1==test2);  // ==>false
        System.out.println(test1.equals(test2));  // ==>true


用equals方法时前面那个变量(比如此处的test1)一定不能是Null,否则会报错。

可以用短路运算符test1 != Null && test1.equals(test2),也可以把前者写成无论如何都不会是Null的变量。



Switch语句:

和C语言基本一致。

没有花括号,case穿透,default等特性也被保留。

匹配字符串时是保证内容相等。


Java12新特性:类似模式匹配。

用新语法可以不写break也保证一一对应。

        switch (test1){
            case "hello" -> System.out.println("hello");
            case "miao", "wang" -> {
                System.out.println("miao");  // 花括号可以写多条语句
                System.out.println("wang");
            }
            default -> System.out.println("23333");
        }
还可以用新特性直接赋值。


        int num2333 = switch (test1){
            case "hello" -> 1;
            case "miao" -> 2;
            default -> {
                System.out.println("miao");
                yield 0;   // 有多条语句时用yield返回返回值
            }
        };

while循环和do while循环与C语言一致。


for循环


和C语言的for循环基本一致。

计数器i要尽量定义在for循环的括号内部,变量最小化原则。


for each循环

和python的for xxx in xxx比较相似

for (String sss1:names){
            System.out.println(sss1);
}
有时候前面的变量类型也可以换做var(更像python的for循环了


continue和break语句也和C语言一致。


打印数组:

使用循环遍历打印。

直接打印是JVM中的引用地址。

也可以用现有的方法Arrays.toString(数组)

Arrays.sort(数组)排序  默认从小到大  数组里未定义的默认为0  方法直接对数组进行操作,不是返回值。


二维数组

除了定义的时候不像C语言那样必须写长度,其他基本一致

转换字符串Arrays.deepToString(数组)


命令行参数

是String数组,会把运行命令行时附加的参数以空格隔开放到一个字符串数组里面。



Java面向对象


一个Java源文件只能定义一个Public类

class Person{
    public String name;
    public  int age;
}
...

Person p1 = new Person();
p1.name = "红";
p1.age = 18;
System.out.printf("%d, %s",p1.age,p1.name);


if(string == null | string.isBlank())  判断字符串是否为null或者为空


this  没有命名冲突时可以省略this,与C++基本一致。


方法参数:必须按照定义严格依次填写。

可变参数:数组,用类型...定义,比如String...

可变参数可以保证调用方无法传入null


构造方法:基本与C++一致。

没有构造方法时使用默认的构造方法。

想要两种不同参数的构造方法,就同时写两个构造(类似于C++的重载)

一个构造方法可以调用其他构造方法,便于代码复用。 this(string);

默认构造方法构造出来的默认值,引用类型是null,整型是0,布尔型是false

构造方法可以重载,里面写的其他方法也可以重载。


Java可以用extends关键字来继承父类

class Student extends Person{}

继承后默认就有了父类的所有字段,所以不能定义和父类同名的字段。

没写extends的时候相当于自动加上了extends Object。


直接继承无法访问父类的private方法或者字段,可以改为protected


子类引用父类字段时,可以写super.xxx


构造子类时,如果没写父类的构造方法,相当于默认加一个super()

当父类没有这种无参的构造方法时就会报错。

所以可以在子类构造时手动调用父类的构造方法super(name, age)


阻止继承

java15新增sealed修饰class,可以写明那些类可以继承这个类。

public sealed class Person permits Student, Teacher{}

这样就是只允许Student类和Teacher类继承Person。继承时要在前面用final、non-sealed或者sealed修饰class。


向上转型

子类安全的变为父类

Person p1 = new Student();


向下转型

Person p1 = new Student();

Student s1 = (Student) p1;

向下转型可能会失败,报错ClassCastException

instanceof 判断是否是制定类型或其子类 if(p1 instance of Person)           null永远是false

java14开始可以判断之后直接转换

if(p1 instance of Student s){可以直接使用变量s}


组合与继承的区分



Override重写,子类和父类相同的方法名、返回值,相同的参数。

Overload重载,子类和父类相同的方法名、返回值,不同的参数。

可以在方法前加上@Override或者@Overload来让编译器帮你检查是否写错了。


多态:动态调用方法。


重写Object方法

Srting toString()

boolean equals(Object o)

hashCode()


final修饰的方法不能被重写

final修饰的类不能被继承

final修饰的字段不能被修改


抽象方法:不需要具体实现

public abstract void run();

抽象方法必须写在抽象类中

abstract class Person {}

抽象类无法被实例化


面向抽象编程


接口

如果抽象类没有字段,全都是抽象方法,就可以把抽象类写为interface接口

接口比抽象类还抽象,不能有字段,所有方法都是public abstract(因此可以省略)

用类来实现接口时,不是继承extends,而是implements实现。

一个类只能从另一个类继承,但是可以写多个接口的实现。用逗号隔开。

接口继承接口使用extends

default方法,需要写实现。可以调用抽象类里面的方法,这样只要复写抽象类的方法就能保证default方法不变。


静态static

静态字段:类里面共享的字段。静态字段不属于实例。推荐使用类名.静态字段来访问。

静态方法:不需要实例变量,通过类名即可调用。

接口可以有静态字段,必须用final修饰:public static final int NUM = 1;

因为接口中静态字段默认都是public static final,所以可以省略,直接写int效果是一样的。


包package

第一行声明包名package com.company;

包名和文件路径有对应关系。

包没有父子关系,java.util和java.util.zip是两个不同的包。

包作用域:不用public、protected或者privata修饰的方法就是包的作用域,仅限同一个包里访问。


导包

①写出完整类名调用。

②import包然后写简单类名。

import static 导入所有静态类和静态方法

简单类名查找顺序:包里面、import导入的、java.lang里面的

如果两个包里面有类名冲突,则只能导其中的一个

写包时通常采用倒置域名的方式确保唯一性。


嵌套类

内部类Inner Class:定义在一个class内部的class

不能单独存在,依附于外部类Outer Class

Outer outer = new Outer("Nested"); // 实例化一个Outer
Outer.Inner inner = outer.new Inner(); // 实例化一个Inner
要实例化内部类,必须先创建外部类,然后调用外部实例的new方法来实例化内部类


内部类可以访问外部类的private属性和方法

静态内部类:static修饰

不再依附于外部类实例,是一个完全独立的类,但是可以访问外部类的静态字段和静态方法。


匿名类:Anonymous class

在方法内部通过匿名类定义。

接口不能实例化,但是可以实现接口的匿名类,通过new来实例化匿名类


jar包:本质是ZIP,处理类之间的关系。

模块jmod,处理jar包之间的依赖关系。


字符串比较相等用equals()

忽略大小写equalsIgnoreCase()

是否包含子串contains()

序号indexOf()

倒序lastIndexOf()

开头startsWith()

结尾endsWith()

切片substring(2)  类似python的str[2:]

substring(2, 4)  类似python的str[2:4]

去除首尾空白字符(\r\n\t等)trim

strip,去除首尾空白字符,包括中文空格\u3000

stripLeading()去首  srtipTeailing() 去尾

isEmpty空字符(长度为0)isBlank()只包含空白字符

如果为null则会引发异常。

替换字符串

.replace(a,b) replace替换

replaceAll(正则.b) 正则替换

分割字符串

分割成字符串数组,传入正则表达式

String[] ss = s.split("\\,")

拼接字符串:用指定的字符串连接字符串数组

String s = String.join(", ", strArry)  // 逗号分隔


格式化字符串

格式化字符串.formatted(参数列表)

或者静态方法String.format("格式化字符串", 参数列表)


转化为字符串

String s = String.valueOf()

getInteger是把系统变量转换为数字

Integer.getInteger("java.version"); // 版本号,11

要把字符串转换为数字

Integer.parseInt("ff", 16)  // 以16进制载入

char[] cs ="miao".toCahrArray()  转换为char[]

String s = new String(cs)  转换为字符串


Java字符串可以直接相加,但是每次相加都是生成新字符串,效率较低。

可以使用StringBuilder

StringBuilder sb = new StringBuilder(1024);

sb.append(","); sb.append("miao");

String s = sb.toString();

也可以链式操作sb.append().append().append().insert(0, "Hello")

定义中返回this就可以实现这种链式操作。


StringJoiner()字符串列表的字符串拼接。

var sj = new StringJoiner(",", "开头","结尾")

sj.add("要加的内容")

sj.toString(); 转换为字符串。

还有String.join()的静态方法


包装类

可以把基本类型视为对象(引用类型)

只包含一个实例字段。

java核心库自带包装类型

java.lang.Boolean

java.lang.Byte

java.lang.Short

java.lang.Integer

java.lang.Long

java.lang.Float

java.lang.Double

java.lang.Character


通过静态方法valueOf()创建Integer实例(另一个parseInt()返回的是int型)


所有包装类都是不变类,作为引用类型不能用==比较,而是用equals比较。


枚举类

可以用enum标记

enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT}

enum Weekday {SUN(7), MON(1), ....}

这样写括号的话就相当于调用自己类的构造函数,括号里面是参数

可以自己定义一个public变量,初始化的时候构造函数赋值

public final int dayValue;

private Weekday(int dayValue){this.dayValue=dayValue;}

枚举类可以用equals,也可以直接用==来比较相等!

Weekday.SUN.name();  // "SUN"

Weekday.SUN.ordinal();  // 1


record类

java14引入

public record Point(int x, int y){}

这个类除了用final修饰每个字段外,还自动构建了toString euqals hashCode等方法。

如果构造时要检查值对不对,可以自己编写构建,但是不需要自己赋值,编译器会自己加上。

也可以自己添加静态方法。


BigInteger 可以定义非常大的数

做运算时只能用实例方法。

BigDecimal任意大小精度完全准确的浮点数。

比较必须用compareTo()而不用equals(),因为equals会同时比较精度信息。


Math.abs();绝对值

Math.max();Math.min(); 比较两个数中最大的和最小的

Math.pow(x,y); 计算x的y次方

Math.sqrt(); 开根号

Math.exp(); e的x次方

Math.log()  以e为底的对数

Math.log10() 以10为底的对数

sin cos tan asin acos 三角函数

Math.PI π  MAth.E e 

Math.random() 随机生成一个大于等于0小于1的数。



异常处理

try {
    String s = processFile(“C:\\test.txt”);
    // ok:
} catch (FileNotFoundException e) {
    // file not found:
} catch (SecurityException e) {
    // no read permission:
} catch (IOException e) {
    // io error:
} catch (Exception e) {
    // other error:
}
错误(Error)是严重错误,如内存耗尽(OutOfMemoryError)、栈溢出等,程序一般无能为力。


Exception是运行时错误,可以被捕获和处理。

分为RuntimeException和其他(IOException、ReflectiveOperationException等)

除RuntimeException及其子类,都是必须捕获的异常。

不需要捕获的异常包括Error及其子类,RuntimeExcep及其子类


不想写try,可以把main()后面加上throws Exception

e.printStackTrace() 打印异常栈


抛出异常

throw new IllegalArgumentException(e)

可以捕获并传递上一个异常e,这样可以获取完整的异常信息。

常用异常:

Exception

├─ RuntimeException
│  │
│  ├─ NullPointerException
│  │
│  ├─ IndexOutOfBoundsException
│  │
│  ├─ SecurityException
│  │
│  └─ IllegalArgumentException
│     │
│     └─ NumberFormatException

├─ IOException
│  │
│  ├─ UnsupportedCharsetException
│  │
│  ├─ FileNotFoundException
│  │
│  └─ SocketException

├─ ParseException

├─ GeneralSecurityException

├─ SQLException

└─ TimeoutException


IO InputStream OutputStream

File对象

既可以表示文件,也可以表示路径。

File f = new File("路径")

f.getPath()  f.getAbsolutePath() f.getCanonicalPath() 传入的路径 绝对路径 规范路径


File.separator 根据操作系统平台打印/或者\

isFile()

isDirectory()

canRead  canWrite  canExecute length文件字节大小

createNewFile()创建新文件  file.delete()删除文件(如果是路径需要保证路径为空才能删除)

File f = File.createTempFile("");

f.deleteOnExit();

创建临时文件,JVM退出时自动删除


mkdir() 创建路径  mkdirs() 套娃创建路径

list() listFiles() 列出目录的文件和子目录名

listFiles可以重载accept方法来筛选文件。


InputStream基本输入流

用close()方法来关闭流。

异常处理可以写finally里面,也可以用try(InputStream dd = new FileInputStream("文件名")){}这样编译器可以自动关闭流。

定义缓冲区 byte[] buffer = new byte[1000];

read(buffer)方法读取数据时会造成阻塞,等这一天执行完才执行下一条语句。

FileInputStream


OutputStream基本输出流

write()

close()方法关闭

flush()强制写入缓冲区

FileOutputStream


Reader 输入流接口(字符流)

Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8); //指定编码


try (Reader reader = new InputStreamReader(new FileInputStream("src/readme.txt"), "UTF-8")) {
    // TODO:
}

Writer 输出流


集合list

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("apple"); // size=1
        list.add(null); // size=2
        list.add("pear"); // size=3
        String second = list.get(1); // null
        System.out.println(second);
    }
}
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
            String s = it.next();
            System.out.println(s);


hashMap

Map<String, Student> map = new HashMap<>();
map.put("Xiao Ming", s); // 将"Xiao Ming"和Student实例映射并关联 Student target = map.get("Xiao Ming"); // 通过key查找并返回映射的Student实例




本文作者:赵苦瓜      文章标题: 【点滴记录】Java的初步入门(更新中)
本文地址:https://blog.jixiaob.cn/?post=79
版权声明:若无注明,本文皆为“赵苦瓜のBlog~”原创,转载请保留文章出处。

返回顶部    首页    后花园  
版权所有:赵苦瓜のBlog~    站长: 赵苦瓜    主题寒光唯美式V2.4.1  程序:emlog   鲁ICP备20030743号-1  萌ICP备20222268号    sitemap