【学习笔记】java学习笔记

admin 2022年12月3日16:28:09评论9 views字数 9986阅读33分17秒阅读模式

[huayang]

变量和数据类型

在 Java 中,变量必须先定义后使用,在定义变量的时候,可以给它一个初始值

注意到第一次定义变量 x 的时候,需要指定变量类型 int,因此使用语句 int x = 100;。而第二次重新赋值的时候,变量 x 已经存在了,不能再重复定义,因此不能指定变量类型 int,必须使用语句 x = 200;

基本数据类型整数类型:byte,short,int,long浮点数类型:float,double (double与float的区别取值范围和字节数 Double更大)字符类型:char布尔类型:boolean

注意 char 类型使用单引号',且仅有一个字符,要和双引号 " 的字符串类型区分开

【学习笔记】java学习笔记
【学习笔记】java学习笔记

常量在定义时进行初始化后就不可再次赋值,再次赋值会导致编译错误。

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

定义变量时,要遵循作用域最小化原则,尽量将变量定义在尽可能小的作用域,并且,不要重复使用变量名

整数运算

特别注意:整数的除法对于除数为 0 时运行时将报错,但编译不会报错。

移位运算

在计算机中,整数总是以二进制的形式表示

比如:

<< 表示向左位移一位  
【学习笔记】java学习笔记
【学习笔记】java学习笔记
>> 表示向右位移一位
【学习笔记】java学习笔记
【学习笔记】java学习笔记

还有一种无符号的右移运算,使用 >>>,它的特点是不管符号位,右移后高位总是补 0

int n = -536870912;int a = n >> 1;  // 11110000 00000000 00000000 00000000 = -268435456int b = n >> 2;  // 11111000 00000000 00000000 00000000 = -134217728int c = n >> 28; // 11111111 11111111 11111111 11111110 = -2int d = n >> 29; // 11111111 11111111 11111111 11111111 = -1

位运算

与运算,符号为|,1|1 为 1 反之都为 0

或运算,符号为 &,0&0 为 0 反之都为 1

异或运算,符号为 ^,同为 0 异为 1

在Java的计算表达式中,运算优先级从高到低依次是:()! ~ ++ --* / %+ -<< >> >>>&|+= -= *= /=记不住也没关系,只需要加括号就可以保证运算的优先级正确。

在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型

要注意,超出范围的强制转型会得到错误的结果,原因是转型时,int 的两个高位字节直接被扔掉,仅保留了低位的两个字节

因此,强制转型的结果很可能是错的。

浮点数运算

浮点数运算和整数运算相比,只能进行加减乘除这些数值计算,不能做位运算和移位运算。

在计算机中,浮点数虽然表示的范围大,但是,浮点数有个非常重要的特点,就是浮点数常常无法精确表示。

可以将浮点数强制转型为整数。在转型时,浮点数的小数部分会被丢掉。如果转型后超过了整型能表示的最大范围,将返回整型的最大值

布尔运算

布尔运算是一种关系运算,包括以下几类:

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

关系运算符的优先级从高到低依次是:

  • !
  • >>=<<=
  • ==!=
  • &&
  • ||

短路运算

布尔运算的一个重要特点是短路运算。如果一个布尔运算的表达式能提前确定结果,则后续的计算不再执行,直接返回结果。

三元运算符

int n = -100;        int x = n >= 0 ? n : -n;//n=100

字符和字符串

在 Java 中,字符和字符串是两个不同的类型。

Java 在内存中总是使用 Unicode 表示字符

转义字符 \

字符串连接

使用 + 连接任意字符串和其他数据类型

如果用 + 连接字符串和其他数据类型,会将其他数据类型先自动转型为字符串

从 Java 13 开始,字符串可以用 """...""" 表示多行字符串(Text Blocks)了

不可变特性

数组类型

 // 5位同学的成绩:        int[] ns = new int[5];        ns[0] = 68;        ns[1] = 79;        ns[2] = 91;        ns[3] = 85;        ns[4] = 62;

可以用数组变量.length 获取数组大小

  // 5位同学的成绩:        int[] ns = new int[5];        System.out.println(ns.length); // 5

也可以在定义数组时直接指定初始化的元素,这样就不必写出数组大小

int[] ns = new int[] { 68, 79, 91, 85, 62 };

还可以进一步简写为:

int[] ns = { 68, 79, 91, 85, 62 };

输入和输出

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

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

由于 % 表示占位符,因此,连续两个 %% 表示一个 % 字符本身。

if 判断

引用类型判断内容相等要使用 equals()

switch 多重选择

如果 option 的值没有匹配到任何 case,这时,可以给 switch 语句加一个 default,当没有匹配到任何 case 时,执行 default

public class Main {    public static void main(String[] args) {        int option = 99;        switch (option) {        case 1:            System.out.println("Selected 1");            break;        case 2:            System.out.println("Selected 2");            break;        case 3:            System.out.println("Selected 3");            break;        default:            System.out.println("Not selected");            break;        }    }}

使用 switch 时,注意 case 语句并没有花括号 {},而且,case 语句具有 “穿透性”,漏写 break 将导致意想不到的结果

如果有几个 case 语句执行的是同一组语句块,可以这么写:

public class Main {    public static void main(String[] args) {        int option = 2;        switch (option) {        case 1:            System.out.println("Selected 1");            break;        case 2:        case 3:            System.out.println("Selected 2, 3");            break;        default:            System.out.println("Not selected");            break;        }    }}

switch 语句还可以匹配字符串

switch 表达式

从 Java 12 开始,switch 语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要 break 语句

public class Main {    public static void main(String[] args) {        String fruit = "apple";        int opt = switch (fruit) {            case "apple" -> 1;            case "pear", "mango" -> 2;            default -> 0;        }; // 注意赋值语句要以;结束        System.out.println("opt = " + opt);    }}

注意新语法使用 ->,如果有多条语句,需要用 {} 括起来。不要写 break 语句,因为新语法只会执行匹配的语句,没有穿透效应。

yield

返回

while 循环

while (条件表达式) {    循环语句}// 继续执行后续代码

注意到 while 循环是先判断循环条件,再循环,因此,有可能一次循环都不做

do while 循环

do while 循环则是先执行循环,再判断条件,条件满足时继续循环,条件不满足时退出。它的用法是:

do {    执行循环语句} while (条件表达式);

for 循环

使用 for 循环时,计数器变量 i 要尽量定义在 for 循环中

for each 循环

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

break 和 continue

break

在循环过程中,可以使用 break 语句跳出当前循环

要特别注意,break 语句总是跳出自己所在的那一层循环

continue

continue 则是提前结束本次循环,直接继续执行下次循环

遍历数组

打印数组内容

Java 标准库提供了 Arrays.toString(),可以快速打印数组内容

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));    }}

数组排序

实际上,Java 的标准库已经内置了排序功能,我们只需要调用 JDK 提供的 Arrays.sort() 就可以排

import java.util.Arrays;public class Main {    public static void main(String[] args) {        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };        Arrays.sort(ns);        System.out.println(Arrays.toString(ns));    }}

多维数组

二维数组

二维数组就是数组的数组。定义一个二维数组如下:

public class Main {    public static void main(String[] args) {        int[][] ns = {            { 1, 2, 3, 4 },            { 5, 6, 7, 8 },            { 9, 10, 11, 12 }        };        System.out.println(ns.length); // 3    }}

打印一个二维数组使用 Java 标准库的 Arrays.deepToString()

import java.util.Arrays;public class Main {    public static void main(String[] args) {        int[][] ns = {            { 1, 2, 3, 4 },            { 5, 6, 7, 8 },            { 9, 10, 11, 12 }        };        System.out.println(Arrays.deepToString(ns));    }}

三维数组

三维数组就是二维数组的数组。可以这么定义一个三维数组:

int[][][] ns = {    {        {1, 2, 3},        {4, 5, 6},        {7, 8, 9}    },    {        {10, 11},        {12, 13}    },    {        {14, 15, 16},        {17, 18}    }};

面向对象基础

定义 class

在 Java 中,创建一个类,例如,给这个类命名为 Person,就是定义一个 class

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

一个 class 可以包含多个字段(field),字段用来描述一个类的特征。上面的 Person 类,我们定义了两个字段,一个是 String 类型的字段,命名为 name,一个是 int 类型的字段,命名为 age。因此,通过 class,把一组数据汇集到一个对象上,实现了数据封装。

public 是用来修饰字段的,它表示这个字段可以被外部访问

在 OOP 中,class 和 instance 是 “模版” 和 “实例” 的关系;

定义 class 就是定义了一种数据类型,对应的 instance 是这种数据类型的实例;

class 定义的 field,在每个 instance 都会拥有各自的 field,且互不干扰;

通过 new 操作符创建新的 instance,然后用变量指向它,即可通过变量来引用这个 instance

指向 instance 的变量都是引用变量。

访问实例变量可以用变量.字段

Person ming = new Person();ming.name = "Xiao Ming"; // 对字段name赋值ming.age = 12; // 对字段age赋值System.out.println(ming.name); // 访问字段namePerson hong = new Person();hong.name = "Xiao Hong";hong.age = 15;

方法

为了避免外部代码直接去访问 field,我们可以用 private 修饰 field,拒绝外部访问

把 field 从 public 改成 private,外部代码不能访问这些 field

我们需要使用方法(method)来让外部代码可以间接修改 field

  • 方法内部遇到 return 时返回,void 表示不返回任何值(注意和返回 null 不同);
  • 外部代码通过 public 方法操作实例,内部代码可以调用 private 方法;
  • 理解方法的参数绑定。

this 变量

它始终指向当前实例。因此,通过 this.field 就可以访问当前实例的字段

如果没有命名冲突,可以省略 this

构造方法

public class Main {    public static void main(String[] args) {        // TODO: 给Person增加构造方法:        Person ming = new Person("小明", 12);/** 等同于Person ming = new Person(); ming.setName("小明"); ming.setAge(12);**/        System.out.println(ming.getName());        System.out.println(ming.getAge());    }}class Person {    private String name;    private int age;    public Person(String n,int a){    name = n;    age = a;    }    public String getName() {        return name;    }    public int getAge() {        return age;    }}

没有定义构造方法时,编译器会自动创建一个默认的无参数构造方法;

可以定义多个构造方法,编译器根据参数自动判断;

可以在一个构造方法内部调用另一个构造方法,便于代码复用。

方法重载

多个相同名称的方法如果想在同一个类中共存,那么这些同名的方法一定是参数的个数或者参数的数据类型不一样,这种同名的方法就叫做重载(Overload)

方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。

继承

Java 使用 extends 关键字来实现继承

class Person {    private String name;    private int age;    public String getName() {...}    public void setName(String name) {...}    public int getAge() {...}    public void setAge(int age) {...}}class Student extends Person {    // 不要重复name和age字段/方法,    // 只需要定义新增score字段/方法:    private int score;    public int getScore() { … }    public void setScore(int score) { … }}

多态

若编译时的类型和运行时的类型不一样就会出现多态

在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写(Override)。

在子类Student中,覆写这个run()方法:class Student extends Person {    @Override    public void run() {        System.out.println("Student.run");    }}

注意:方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在 Java 程序中,出现这种情况,编译器会报错。

【学习笔记】java学习笔记

小结

  • 子类可以覆写父类的方法(Override),覆写在子类中改变了父类方法的行为;
  • Java 的方法调用总是作用于运行期对象的实际类型,这种行为称为多态;
  • final 修饰符有多种作用:
    • final 修饰的方法可以阻止被覆写;
    • final 修饰的 class 可以阻止被继承;
    • final 修饰的 field 必须在创建对象时初始化,随后不可修改。

抽象类

由于多态的存在,每个子类都可以覆写父类的方法

抽象类中有一个抽象方法就必须是抽象类,抽象方法用ABSTRACT修饰。

因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。

使用 abstract 修饰的类就是抽象类。我们无法实例化一个抽象类:

abstract class Person {    public abstract void run();}
Person p = new Person(); // 编译错误

定义了抽象的方法要实现类的时候就必须要复写

  • 如果不实现抽象方法,则该子类仍是一个抽象类;

面向抽象编程

面向抽象编程的本质就是:

  • 上层代码只定义规范(例如:abstract class Person);
  • 不需要子类就可以实现业务逻辑(正常编译);
  • 具体的业务逻辑由不同的子类实现,调用者并不关心。

接口

如果一个抽象类没有字段,所有方法全部都是抽象方法:

abstract class Person {    public abstract void run();    public abstract String getName();}

就可以把该抽象类改写为接口:interface

在 Java 中,使用 interface 可以声明一个接口:

interface Person {    void run();    String getName();}

接口定义的所有方法默认都是 public abstract 的,所以这两个修饰符不需要写出来(写不写效果都一样)

当一个具体的 class 去实现一个 interface 时,需要使用 implements 关键字。

class Student implements Person {    private String name;    public Student(String name) {        this.name = name;    }    @Override    public void run() {        System.out.println(this.name + " run");    }    @Override    public String getName() {        return this.name;    }}

一个类可以实现多个 interface,多个接口用,分隔

如果类没有实现接口所有方法,那么这个类就要定义抽象类

接口继承

一个 interface 可以继承自另一个 interfaceinterface 继承自 interface 使用 extends,它相当于扩展了接口的方法。

先写继承后写实现

【学习笔记】java学习笔记

静态字段和静态方法

在一个 class 中定义的字段,我们称之为实例字段。实例字段的特点是,每个实例都有独立的字段,各个实例的同名字段互不影响。

还有一种字段,是用 static 修饰的字段,称为静态字段:static field

class Person {    public String name;    public int age;    // 定义静态字段number:    public static int number;}

对于静态字段,无论修改哪个实例的静态字段,效果都是一样的

静态方法

有静态字段,就有静态方法。用 static 修饰的方法称为静态方法

在 Java 中,我们使用 package 来解决名字冲突。

package ming; // 申明包名mingpublic class Person {}
【学习笔记】java学习笔记

import

在一个 class 中,我们总会引用其他的 class

第一种,直接写出完整类名,例如:

// Person.javapackage ming;public class Person {    public void run() {        mr.jun.Arrays arrays = new mr.jun.Arrays();    }}

第二种写法是用 import 语句,导入小军的 Arrays,然后写简单类名:

// Person.javapackage ming;// 导入完整类名:import mr.jun.Arrays;public class Person {    public void run() {        Arrays arrays = new Arrays();    }}

在写 import 的时候,可以使用 *,表示把这个包下面的所有 class 都导入进来(但不包括子包的 class):

【学习笔记】java学习笔记

作用域

我们经常看到 publicprotectedprivate 这些修饰符。在 Java 中,这些修饰符可以用来限定访问作用域。

public

定义为 public 的 classinterface 可以被其他任何类访问

private

定义为 private 的 fieldmethod 无法被其他类访问

protected

protected 作用于继承关系。定义为 protected 的字段和方法可以被子类访问,以及子类的子类

上面的 protected 方法可以被继承的类访问

package xyz;class Main extends Hello {    void foo() {        // 可以访问protected方法:        hi();    }}

package

包作用域是指一个类允许访问同一个 package 的没有 publicprivate 修饰的 class,以及没有 publicprotectedprivate 修饰的字段和方法

package abc;// package权限的类:class Hello {    // package权限的方法:    void hi() {    }}

只要在同一个包,就可以访问 package 权限的 classfield 和 method

package abc;class Main {    void foo() {        // 可以访问package权限的类:        Hello h = new Hello();        // 可以调用package权限的方法:        h.hi();    }}

局部变量

在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束

final

用 final 修饰 class 可以阻止被继承

package abc;// 无法被继承:public final class Hello {    private int n = 0;    protected void hi(int t) {        long i = t;    }}

用 final 修饰 method 可以阻止被子类覆写

package abc;public class Hello {    // 无法被覆写:    protected final void hi() {    }}

用 final 修饰 field 可以阻止被重新赋值

package abc;public class Hello {    private final int n = 0;    protected void hi() {        this.n = 1; // error!    }}

用 final 修饰局部变量可以阻止被重新赋值:

package abc;public class Hello {    protected void hi(final int t) {        t = 1; // error!    }}

最佳实践

如果不确定是否需要 public,就不声明为 public,即尽可能少地暴露对外的字段和方法。

把方法定义为 package 权限有助于测试,因为测试类和被测试类只要位于同一个 package,测试代码就可以访问被测试类的 package 权限方法。

一个.java 文件只能包含一个 public 类,但可以包含多个非 public 类。如果有 public 类,文件名必须和 public 类的名字相同。

内部类(Inner Class)

如果一个类定义在另一个类的内部,这个类就是 Inner Class:

class Outer {    class Inner {        // 定义了一个Inner Class    }}

上述定义的 Outer 是一个普通类,而 Inner 是一个 Inner Class,它与普通类有个最大的不同,就是 Inner Class 的实例不能单独存在,必须依附于一个 Outer Class 的实例。示例代码如下:

public class Main {    public static void main(String[] args) {        Outer outer = new Outer("Nested"); // 实例化一个Outer        Outer.Inner inner = outer.new Inner(); // 实例化一个Inner        inner.hello();    }}class Outer {    private String name;    Outer(String name) {        this.name = name;    }    class Inner {        void hello() {            System.out.println("Hello, " + Outer.this.name);        }    }}

[/huayang]

FROM:浅浅淡淡[hellohy]

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月3日16:28:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【学习笔记】java学习笔记https://cn-sec.com/archives/1443058.html

发表评论

匿名网友 填写信息