# Java基础

# java的应用

java分为三个版本 javaSE javaEE javaME

  • javaSE 是java语言的标准版,可用于桌面端的开发,是其他两个版本的基础
  • javaEE 是java语言的企业版,可用于web方向的网站开发,如web开发、分布式开发、移动开发等
  • javaME 是java语言的小型版,可用于嵌入式电子系统,如手机、平板等

# 数据类型

# 基本数据类型

# 整数数据类型(取值范围不同)常用 int

  • byte (取值范围为:-128~127)
  • short (取值范围为:-32768~32767)
  • int (取值范围为:-2147483648~2147483647)
  • long (取值范围为:-9223372036854775808~9223372036854775807)

    注意:

    long类型数据需要加L或l作为后缀

# 浮点数(小数类型常用 double)

  • float (取值范围为:-3.4028235E38~3.4028235E38)
  • double (取值范围为:-1.7976931348623157E308~1.7976931348623157E308)

    注意:

    float类型数据需要加F或f作为后缀

# 字符

  • char (取值范围为:0~65535)

    拓展

    小数和整数数据类型取值范围:double>float>int>long>short>byte

# 布尔值

  • boolean (取值为:true、false)

# 处理数字精度的数据类型

  • BigDecimal(高精度数据类型) 是 Java 中用于精确计算的高精度数值类型,特别适合处理金融、货币等需要避免浮点数精度误差的场景。

# 为什么需要BigDecimal

  1. 浮点数精度问题
System.out.println(0.1 + 0.2); // 输出 0.30000000000000004
  • float/double 基于 IEEE 754 标准,无法精确表示所有十进制小数,会导致金额计算等场景出现精度丢失
  1. BigDecimal 优势
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 精确输出 0.3

# 创建 BigDecimal 的正确方式

// 1. 字符串构造(最安全)
BigDecimal d1 = new BigDecimal("0.1"); 

// 2. 使用 valueOf(内部调用 toString)
BigDecimal d2 = BigDecimal.valueOf(0.1); 

注意

  • 浮点数构造会带入精度误差!
  • BigDecimal d3 = new BigDecimal(0.1);
  • 实际值可能是 0.100000000000000005551115...

# 基本运算与精度控制

  1. 四则运算(返回新对象)
BigDecimal num1 = new BigDecimal("10");
BigDecimal num2 = new BigDecimal("3");

BigDecimal sum = num1.add(num2);      // 加法: 13
BigDecimal diff = num1.subtract(num2); // 减法: 7
BigDecimal product = num1.multiply(num2); // 乘法: 30
  1. 除法必须指定精度和舍入模式

注意

除法必须指定舍入,否则遇到无限小数会抛出 ArithmeticException

// 错误:无限小数会抛出 ArithmeticException
// BigDecimal result = num1.divide(num2); 

// 正确:指定保留3位小数,四舍五入
BigDecimal quotient = num1.divide(num2, 3, RoundingMode.HALF_UP); // 3.333

//设置小数位数
BigDecimal num = new BigDecimal("3.14159");

// 保留两位小数(四舍五入)
BigDecimal scaled = num.setScale(2, RoundingMode.HALF_UP); // 3.14

// 直接截断
BigDecimal truncated = num.setScale(2, RoundingMode.DOWN); // 3.14(若为 3.149→3.14)

舍入模式

模式 规则 示例
HALF_UP 四舍五入(常用) 2.35 → 2.4
HALF_DOWN 五舍六入 2.35 → 2.3
HALF_EVEN 银行家舍入(四舍六入五取偶) 2.35 → 2.4,2.45 → 2.4
UP 远离零方向舍入 -1.1 → -1.2
DOWN 向零方向舍入 -1.1 → -1.0
CEILING 向正无穷方向舍入 1.1 → 2.0,-1.9 → -1.0
FLOOR 向负无穷方向舍入 1.9 → 1.0,-1.1 → -2.0
  1. 比较与相等性
  • 比较值大小(用 compareTo()
BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00");
x.compareTo(y);  // 返回 0(数值相等)

这个方法返回一个整数,表示两个BigDecimal对象在数值上的大小关系。

  1. 返回 -1 表示当前对象小于参数对象。

  2. 返回 0 表示当前对象等于参数对象。

  3. 返回 1 表示当前对象大于参数对象。

  • 避免使用 equals()
x.equals(y); // false(因为精度不同:1.0的scale=1, 1.00的scale=2)

# 运算符

# 算数运算符

  • 加减乘除 + - * /

    注意

    除法运算符 /

    • 当运算符两边都是整数时,结果是整数
    • 除法运算符通常是向下取整
    • 当运算符两边都是小数时,结果是小数 :::
  • 取余 %

    注意

    在代码中如果有小数参与运算,结果可能是不精确的

# 隐式转换

在进行算数运算时,数据类型不一样不能直接进行计算,需转成一样的才能进行运算

# 算数运算符的隐式转换

算数运算符隐式转换的两种提升规则

  • 取值范围小的,和取值范围大的进行运算,小的会提升为大的,再进行运算
  • byte < short < int < long < float < double
  • byte、short、char 三种类型的数据在运算的时候,都会提升为int类型,然后再进行运算

# 字符串的“+”操作

  • 当“+”操作中出现字符串时,“+”是字符串连接符,而不是算数运算符了,会将前后数据进行拼接,并产生一个新的字符串
  • 连续进行“+”操作时,从左到右依次执行

# 字符的“+”操作

  • 当字符+字符或数字时,会将字符转换为对应的ASCII码,然后进行运算

# 自增自减运算符

  • a++ 先用再加
  • ++a 先加再用
  public class Test {
    public static void main(String[] args) {
        int a = 1;
        int b = 1;
        System.out.println(a++);//1
        System.out.println(++b);//2
    }
}

# 赋值运算符

  • = 赋值
  • += 累加
  • -= 累减
  • *= 累乘
  • /= 累除
  • %= 累取余

    注意

    除等号运算符外 以上所有运算符都隐藏了一个强制类型转换

# 关系运算符

  • ==
  • !=
  • <
  • =

  • <= 比较运算符的结果都是boolean类型,要么是true要么是false

# 逻辑运算符

  • & 与
  • | 或
  • ^ 异或 相同返回false 不同返回true
  • ! 非 逻辑运算符当两边为数字时,会将两边的数字转为二进制进行与或运算

# 短路运算符

  • && 逻辑与
  • || 逻辑或

# 三元运算符

格式 :条件表达式?表达式1:表达式2

# 源码、反码、补码

# 源码

定义:十进制数据的二进制表现形式,最左边是符号位,符号位为0表示正数,符号位为1表示负数

# 反码

定义:源码的符号位取反,符号位为0表示正数,符号位为1表示负数 反码是解决源码不能计算负数而出现的

计算规则:

  • 正数的反码不变
  • 负数的反码在源码的基础上,符号位不变。数值取反,0变1,1变0

# 补码

补码的出现是为了解决负数计算跨0的问题而出现的
反码+1
一个字节的取值范围是-128~127
补码的计算规则

  • 正数的补码不变 负数的补码在反码的基础上+1
  • 补码还能多记录一个特殊值-128,该数据在1个字节下,没有源码和反码 补码注意点
  • 计算机中的存储和计算都是以补码的形式进行的

# 循环练习

# 求1~5之间的和

public class Test {
    public static void main(String[] args) {
        //1.求1-5之间的和
        int count = 0;
        for (int i = 1; i <= 5; i++) count += i;
        System.out.println(count);//15
    }
}

# 求1~100之间的偶数和

public class Test {
    public static void main(String[] args) {
        int count = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) count += i;
        }
        System.out.println(count);//2550
    }
}

# 键盘录入一个大于等于2的整数x,要求计算该整数的平方根

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个整数");
        int x = sc.nextInt();
        if (x < 2) throw new Error("请输入一个大于等于2的整数");
        int result = 0;
        while (result * result <= x) result++;
        System.out.println(result - 1);
    }
}

# 猜数字小游戏


import java.util.Random;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        int num = r.nextInt(100) + 1;
        Scanner sc = new Scanner(System.in);
        System.out.println("值为" + num);
        while (true) {
            System.out.println("请输入一个整数");
            int inputNum = sc.nextInt();
            if (inputNum > num) System.out.println("猜大了");
            else if (inputNum < num) System.out.println("猜小了");
            else {
                System.out.println("猜对了");
                break;
            }
        }
    }
}

# 数组

定义:是一种容器,可以用来存储同种数据类型的多个值

  • 数组容器在存储数据的时候,需要结合隐式转换考虑
  • int 类型的数组容器(boolean(不能)、byte(能)、short(能)、int(能)、double(不能) )
  • 建议 容器的类型和存储的数据类型保持一致

# 数组的定义

数组的静态初始化

  • 静态初始化以后数组长度不可变
  • 数组的元素类型必须和数组容器的类型一致
  • 格式:数据类型[] 数组名 = new 数据类型[数组长度]{数组元素1,数组元素2,数组元素3,...}
  • 简写格式:数据类型[] 数组名 = {数组元素1,数组元素2,数组元素3,...}
public class Test {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        //简写
        int[] arr2 = {1, 2, 3, 4, 5};
    }
}

# 地址值格式的含义

在定义数组以后,打印该数组发现是地址值

public class Test {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        System.out.println(arr);//[I@1b6d3586
    }
}
  • [ 表示该地地址值存储一个数组
  • I 表示该地址值存储的是一个int类型数组
  • @ 表示一个间隔符号。(固定格式)
  • 1b6d3586 表示该地址值存储的数组的hash值(十六进制)
  • 平时我们习惯将这个整体叫做数组的地址值

# 数组元素的获取

格式 :数组名[下标值]

  • 数组下标从0开始
  • 数组下标不能超过数组长度

# 将数据存储到数组中

格式 :数组名[下标值] = 值

  • 一但覆盖后,原来的数据就不存在了

# 数组遍历

  • 数组遍历:遍历数组中的每一个元素
  • 格式:for(数据类型 变量名 : 数组名){}
public class Test {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        for (int i : arr) System.out.println(i);
    }
}

# 遍历数组并求和

public class Test {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3, 4, 5};
        int count = 0;
        for (int j : arr1) count += j;
        System.out.println(count);
    }
}

# 统计数组里面一共有多少个能被3整除的数

 public class Test {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int count = 0;
        for (int i : arr) i % 3 == 0 && count++;
        System.out.println(count);
    }
}

# 数组的动态初始化

  • 初始化时只指定数组的长度,由系统为数组分配初始值
  • 格式:数据类型[] 数组名 = new 数据类型[数组长度];

# 数组默认初始化规律

  • 整数类型默认初始化值为0
  • 浮点类型默认初始化值为0.0
  • 布尔类型默认初始化值为false
  • 字符类型默认初始化值为\u0000 (空字符串)
  • 引用类型默认初始化值为null

# 遍历数组求和

需求:生成10个1~100的随机数存入数组

  • 求出所有数据的总和
  • 求出所有数据的平均数
  • 统计有多少个数据比平均值小
public class Test {
    public static void main(String[] args) {
        int[] arr = new int[10];
        int count = 0;
        Random r = new Random();
        for (int i : arr) {
            int num = r.nextInt(100) + 1;
            count += num;
            arr[i] = num;
        }
        //和
        System.out.println("和" + count);
        //平均值
        int average = count / arr.length;
        System.out.println("平均值" + average);
        //统计有多少个数据比平均值小
        int count1 = 0;
        for (int i : arr) if (i < average) count1++;
        System.out.println("总共有" + count1 + "个数比平均值小");
    }
}

# 方法重载

  • 在同一个类中,定义了多个同名的方法,这些同名的方法具有相同的功能
  • 每个方法具有不同的参数类型或参数个数,这些同名的方法就构成了重构关系

# 面向对象 类

类的定义

  • 用来描述一类事物的类,专业叫做:javabean类
  • 在javabean类中是不写main方法的
  • 在以前main方法中编写的类叫做测试类
  • 我们可以在测试类中创建javabean类的对象并赋值调用

# 格式

public class Test {
    //1.成员变量(代表属性)
    //2.成员方法(代表行为)
}

注意

  • 类名首字符必须大写,需要见名之意,驼峰模式
  • 一个java文件中可以定义多个类,且只能一个类是public修饰的,而且public修饰的类名必须成为代码文件名
  • 实际开发中建议还是一个文件定义一个class类
  • 成员变量的完整定义的格式是:修饰符 数据类型 变量名称 =初始值一般无需指定初始化值,存在默认值

# 构造方法

  • 构造方法也叫构造器、构造函数
  • 创建对象的时候由虚拟机自动调用,给成员变量进行初始化的
  • 作用:在创建对象的时候给成员变量进行初始化 格式:
public class Text {
    int number;

    private Phone(int number) {
        this.number = number;
    }
}

特点

  • 方法名与类名相同,大小写也要一致
  • 没有返回值类型,连void都没有
  • 没有具体的返回值(不能由return带回结果数据)

# idea快速生成空参、有参构造方法、getter、setter

  • 方法一:快捷键 alt+insfn +alt+ins
  • 方法二:插件PTG 1秒生成标准javabean 快捷键 ctrl+shift+,

# 格斗文字游戏

//people.java类
package text;

import java.util.Random;

public class People {
    //角色姓名
    private String name;
    //角色血量
    private int blod;
    //角色性别
    private char sex;
    //角色长相
    private String appearance;
    //男生长相数组
    String[] manFace = {"风流俊雅", "气宇轩昂", "英俊潇洒", "五官端正", "相貌平平", "喜气洋洋", "大长腿", "高冷", "短发", "长发"};
    //女生长相数组
    String[] womanFace = {"美奂绝伦", "沉鱼落雁", "婷婷玉立", "身材较好", "相貌平平", "相貌简陋", "长发", "短发"};
    //攻击描述
    String[] attackDescArr = {"%s使出一招【普心钉】,转到敌方身后,一掌向%s的灵台穴拍去。",
            "%s使出了一招【游空探爪】,飞起身形自半空中变掌为抓锁向%s。",
            "%s大喝一声,身形下伏,一招【劈雷坠地】,捶向%s双腿",
            "%s运气于掌,一瞬间掌心变得血红,一式【掌心雷】,推向%s。",
            "%s上步抢身,招中套招,一招【劈挂连环】,连环攻向%s",
            "%s阴手翻起阳手跟进,一招【没选拦】,结结实实的捶向%s"
    };
    //受伤描述
    String[] hurtDescArr = {"结果%s退了半步,毫发无损",
            "结果给%s造成一处瘀伤",
            "结果一击命中,%s痛得弯下腰",
            "结果%s痛苦地闷哼了一声,显然受了点内伤",
            "结果%s摇摇晃晃,一跤摔倒在地",
            "结果『轰』的一声,%s口中鲜血狂喷而出",
            "结果%s脸色一下变得惨白,连退了好几步",
            "结果%s一声惨叫,像滩软泥般塌了下去"
    };

    public People(String name, int blod, char sex) {
        this.name = name;
        this.blod = blod;
        setSex(sex);
    }

    public People() {
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
        Random random = new Random();
        if (sex == '男') {
            int r = random.nextInt(manFace.length);
            setAppearance(manFace[r]);
        } else if (sex == '女') {
            int r = random.nextInt(womanFace.length);
            setAppearance(womanFace[r]);
        }
    }

    public String getAppearance() {
        return appearance;
    }

    public void setAppearance(String appearance) {
        this.appearance = appearance;
    }

    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return blod
     */
    public int getBlod() {
        return blod;
    }

    /**
     * 设置
     *
     * @param blod
     */
    public void setBlod(int blod) {
        this.blod = blod;
    }

    //角色发起攻击
    public void attack(People people) {
        Random r = new Random();
        //获取随机攻击描述
        String attackDesc = attackDescArr[r.nextInt(attackDescArr.length)];
        System.out.printf(attackDesc, this.name, people.name);
        //获取随机伤害
        int hurt = r.nextInt(10) + 1;
        //计算剩余血量
        int remainBlode = people.getBlod() - hurt;
        people.setBlod(Math.max(remainBlode, 0));
        //获取受伤描述
        String hurtDesc = "";

        int blod = people.getBlod();
        if (blod > 90) hurtDesc = hurtDescArr[0];
        else if (blod > 80) hurtDesc = hurtDescArr[1];
        else if (blod > 70) hurtDesc = hurtDescArr[2];
        else if (blod > 60) hurtDesc = hurtDescArr[3];
        else if (blod > 50) hurtDesc = hurtDescArr[4];
        else if (blod > 40) hurtDesc = hurtDescArr[5];
        else if (blod > 0) hurtDesc = hurtDescArr[6];
        else hurtDesc = hurtDescArr[7];
        System.out.printf(hurtDesc, people.name);
        System.out.print(",造成" + hurt + "点伤害," + people.name + "剩余" + people.getBlod() + "血量");
        System.out.println();
    }

    //展示角色信息
    public void show() {
        System.out.println("姓名:" + getName() + "  血量:" + getBlod() + "  性别:" + getSex() + "  长相:" + getAppearance());
    }
}


//使用
//main.java
import text.People;

public class Main {
    public static void main(String[] args) {
        //文字攻击
        People people1 = new People("James", 100, '男');
        People people2 = new People("Tom", 100, '女');
        people1.show();
        people2.show();
        while (true) {
            people1.attack(people2);
            if (people2.getBlod() <= 0) {
                System.out.println(people1.getName() + "已经死亡,战斗结束");
                break;
            }
            people2.attack(people1);
            if (people1.getBlod() <= 0) {
                System.out.println(people2.getName() + "已经死亡,战斗结束");
                break;
            }
        }
    }
}


# java关键字

  • 如class 表示定义类
  • 关键字字母全部小写

# class 关键字

用于创建定义一个类 类是java最基本的组成单元

# private 关键字

  • 是一个权限修饰符
  • 可以修饰成员、(成员变量、成员方法)
  • 被private修饰的成员变量、成员方法只能在本类中访问
//声明类
public class phone {
    private int price;
    private String brand;
    private String color;

    public void setPrice(int p) {
        this.price = p;
    }

    public int getPrice() {
        return this.price;
    }

    public void call(String name) {
        System.out.println("正在给" + name + "打电话");
    }

    public void sendMessage(String name) {
        System.out.println("正在给" + name + "发短信");
    }
}


//使用类
public class Main {
    public static void main(String[] args) {
        phone myPhone = new phone();
        myPhone.call("James");//正在给James打电话
        myPhone.setPrice(2399);
        System.out.println("手机机价格是" + myPhone.getPrice());//手机机价格是2399
    }
}

# lambda表达式

  • lambda表达式最基本的应用就是简化匿名表达式的书写
  • 它是jdk8开始后的一种新语法形式
  • lambda表达式只能简化函数式接口的匿名内部类的写法
  • 函数式接口有且仅有一个抽象方法的接口叫函数式接口,接口上方可以加@FunctionalInterface注解,表示该接口是函数式接口
package api;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaText {
    public static void main(String[] args) {
        Integer[] arr = {1, 4, 2, 6, 4, 3, 8, 9, 7, 5};
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        System.out.println(Arrays.toString(arr));


        //使用Lambda表达式简化匿名内部类
        Integer[] arr2 = {1, 4, 2, 6, 4, 3, 8, 9, 7, 5};
        Arrays.sort(arr2, (o1, o2) -> {
            return o1 - o2;
        });
        System.out.println(Arrays.toString(arr2));
    }

}

# 使用

public class LambdaText {
    public static void main(String[] args) {
        scText(new Swim() {
            @Override
            public void swiming() {
                System.out.println("我在游泳");
            }
        });
        //使用lambda表达式简化
        scText(() -> System.out.println("我在游泳"));
    }

    //调用方法的时候如果这个方法的形参是一个接口,那么我们就要传递这个接口的实现类对象
    //如果实现类对象只要用到一次,就可以使用Lambda表达式来简化
    public static void scText(Swim swim) {
        swim.swiming();
    }

    //使用匿名内部类的前提该要是一个接口 不能是抽象类
    @FunctionalInterface //该注解表示这是一个函数式接口,只有一个抽象方法
    interface Swim {
        public abstract void swiming();
        //   public abstract void swimings();报错
    }
}

# Lambda表达式的省略写法

  • 主要思想:可推导,可省略 Lambda表达式的省略写法
  1. 参数类型可以省略不写
  2. 如果只有一个参数,参数类型可以省略,同时()也可以省略
  3. 如果Lambda表达式的方法体只有一行代码,可以省略大括号和return关键字

# 练习


class GF {
    String name;
    int age;
    double height;

    public GF(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public class LambdaText {
        public static void main(String[] args) {
            //练习
            //定义第一个存储字符串的数组 字符短的在前面 长的在后面
            String[] arr3 = {"aaaa", "aa", "a", "aaa", "aaaa"};
            Arrays.sort(arr3, (o1, o2) -> o1.length() - o2.length());
            System.out.println(Arrays.toString(arr3));//[a, aa, aaa, aaaa, aaaa]

            //定义数组并存储一些女朋友对象,利用Arrays中的sort方法进行排序
            //要求:属性有姓名。年龄、身高
            //要求2:按照年龄的大小进行排序,年龄一样的按照身高进行排序,身高一样的按照姓名字母进行排序


            GF[] arr4 = {new GF("小红", 18, 1.68), new GF("小明", 19, 1.70), new GF("小花", 18, 1.68)};
            Arrays.sort(arr4, (o1, o2) ->

            {
                if (o1.age != o2.age) return o1.age - o2.age;
                if (o1.height != o2.height) return (int) (o1.height - o2.height);
                //将字符串按照字典的顺序(Ascii码的顺序)进行比较
                return o1.name.compareTo(o2.name);
            });
            System.out.println(Arrays.toString(arr4));
        }
    }
上次更新: 6/26/2025, 5:17:52 PM