Java基础语法 1.浮点型拓展 1.1浮点类型的舍入误差 浮点类型float, double 的数据不适合在不容许舍入误差 的领域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Main { public static void main(String[] args) { // 定义一个float类型变量f并赋值为0.1 float f = 0.1f; // 定义一个double类型变量d并赋值为1.0除以10,即0.1 double d = 1.0 / 10; System.out.println(f == d); // 输出:false,由于精度差异,比较结果为false float d1 = 2131231231f; // 定义一个float类型变量d2,将d1加1后的结果赋值给d2 float d2 = d1 + 1; System.out.println("d1="+d1); System.out.println("d2="+d2); // 检查d1是否等于d2 if (d1 == d2) { // 如果d1等于d2,输出"d1==d2" System.out.println("d1==d2"); } else { // 如果d1不等于d2,输出"d1!=d2" System.out.println("d1!=d2"); } } } out: false d1=2.13123123E9 d2=2.13123123E9 d1==d2
注:
1.浮点数一般都存在舍入误差,很多数字无法精确表示,其结果只能是接近,但不等于。
2.避免比较中使用浮点数
3.需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal 类
1.2 BigDecimal类 BigDecimal类: 用于高精度数值运算的类,它允许你精确地表示和执行各种数学运算,包括加法、减法、乘法、除法等,而不会丢失精度。
常用方法:
1.BigDecimal(String val):构造方法,将String类型转换成BigDecimal类型数据。
2.BigDecimal(double val):构造方法,将double类型转换成BigDecimal类型数据。
3.BigDecimal(int val):构造方法,将int类型转换成BigDecimal类型数据。
4.BigDecimal add(BigDecimal value):加法,求两个BigDecimal类型数据的和。
5.BigDecimal subtract(BigDecimal value):减法,求两个BigDecimal类型数据的差。
6.BigDecimal multiply(BigDecimal value):乘法,求两个BigDecimal类型数据的积。
7.BigDecimal divide(BigDecimal divisor):除法,求两个BigDecimal类型数据的商。
8.BigDecimal remainder(BigDecimal divisor):求余数,求BigDecimal类型数据除以divisor的余数。
9.BigDecimal max(BigDecimal value):最大数,求两个BigDecimal类型数据的最大值。
10.BigDecimal min(BigDecimal value):最小数,求两个BigDecimal类型数据的最小值。
11.BigDecimal abs():绝对值,求BigDecimal类型数据的绝对值。
12.BigDecimal negate():相反数,求BigDecimal类型数据的相反数。
13.BigDecimal compareTo():比较两个BigDecimal 对象的大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.math.BigDecimal; public class Main{ public static void main(String[] args) { BigDecimal num1 = new BigDecimal("0.1");//字符串带双引号被解释为确切的数值,若不加会存在一个微小的舍入误差 BigDecimal num2 = new BigDecimal("0.2"); BigDecimal num3=num1.multiply(new BigDecimal("2")); BigDecimal sum = num1.add(num2); System.out.println(num3.compareTo(num2)); System.out.println("sum="+sum); } } out: 0 sum=0.3
2.Scanner对象 2.1 创建 Scanner 对象的基本语法: Scanner s = new Scanner(System.in)
通过 Scanner 类的 next() 或nextLine() 方法获取输入的字符串
读取前一般需要使用 hasNext() 或hasNextLine() 判断是否还有输入的数据
2.2 next & nextLine 使用next方式 接收一下输入的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String token = scanner.next(); System.out.println("Next Token: " + token); } scanner.close(); } } in: hello world out: Next Token: hello Next Token: world
使用nextLine方式 接收一下输入的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String token = scanner.nextLine(); System.out.println("Next Token: " + token); } scanner.close(); } } in: hello world out: Next Token: hello world
两者区别:
1.next() 不能得到带有空格的字符串,nextLine()可以获得空白。
2.nextLine():以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
2.3 其他数据类型 如果要输入int、float等类型的数据,在 Scanner 类中也有支持,使用hasNextXxx() 方法、 nextXxx() 方法 来读取
3.可变参数 可变参数的声明:
typeName... parameterName
注:一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Main{ public static void printMax(double... num){ if(num.length==0) { System.out.println("wrong!"); } double result=0; for (int i = 1; i < num.length; i++) { if (num[i] > result) { result = num[i]; } } System.out.println(num[num.length-1]); }; public static void main(String args[]) { printMax(1,2.3,5.0); } } out: 5.0
4.Arrays 类 数组的工具类java.util.Arrays
常用功能:
4.1 打印数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.Arrays; public class Main{ public static void main(String args[]) { int []num=new int[10]; for(int i=0;i<10;i++){ num[i]=i; } System.out.println(Arrays.toString(num)); } } out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4.2 数组排序 1 2 3 4 5 6 7 8 9 10 11 12 import java.util.Arrays; public class Main{ public static void main(String args[]) { int []num= {5,8,9,4,2}; Arrays.sort(num); System.out.println(Arrays.toString(num)); } } out: [2, 4, 5, 8, 9]
4.3 二分法查找 在进行此调用之前对数组进行排序(通 过sort方法等)
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.Arrays; public class Main{ public static void main(String args[]) { int []num= {5,8,9,4,2}; Arrays.sort(num); System.out.println("索引为:"+Arrays.binarySearch(num,4)); } } out: 索引为:1
4.4 将数组转换成List集合 1 2 int []num= {5,2,9,4,2,3,10}; List<int[]> list= Arrays.asList(num);
5.内部类 5.1 成员内部类 实例化内部类,首先需要实例化外部类,通过外部类去调用内部类
注:成员内部类中不能写静态属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ppublic class Test { public static void main(String[] args) { //1.实例化外部类 Outer out=new Outer(); //2.通过外部类调用内部类 Outer.Inner inObject = out.new Inner(); inObject.In(); } } class Outer{ private int id; public void out(){ System.out.println("外部类"); } Outer() { id=10; } class Inner{ private int id; public void In(){ System.out.println("内部类"); } Inner(){ id=1; System.out.println("外部:"+Outer.this.id);//Outer.this.显式调用外部类的变量 System.out.println("内部:"+id);//内部类中的变量会暂时将外部类的成员变量给隐藏 } } } out: 外部:10 内部:1 内部类
5.2 静态内部类 静态内部类能够直接被外部类给实例化,不需要使用外部类对象
静态内部类只能访问自己属性和方法及外部类的静态属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class OuterClass { private static int outerStaticField = 42; // 静态内部类 public static class StaticInnerClass { private int innerField; public StaticInnerClass(int innerField) { this.innerField = innerField; } public void printValues() { System.out.println("Outer static field: " + outerStaticField); System.out.println("Inner field: " + innerField); } } public static void main(String[] args) { // 创建静态内部类的实例 StaticInnerClass innerObj = new StaticInnerClass(10); // 调用静态内部类的方法 innerObj.printValues(); } }
5.3 局部内部类 局部内部类是在一个方法内部声明的一个类
在局部内部类中,如果要访问局部变量 ,那么该局部变量 要用final修饰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class LocalInnerClassTest { // 外部类的成员变量 private String name; private static int age; LocalInnerClassTest(String name,int age) { this.name=name; this.age=age; } // 外部类的实例方法 public void run() {} // 外部类的静态方法 public static void go() {} // 外部类的实例方法,包含局部内部类的定义 public void test() { // 定义一个 final 局部变量 final String myname = "xxx"; // 定义局部内部类 LocalInnerClass class LocalInnerClass { // 局部内部类的成员变量 private String name; // 局部内部类的方法,接受一个参数 name public void test(String name) { // 在方法中访问参数 name System.out.println(name); // 在局部内部类的成员方法中,可以使用 this 关键字访问局部内部类的成员变量 System.out.println(this.name); // 在局部内部类中访问外部方法中的 final 变量 myname System.out.println(myname); // 在局部内部类中访问外部类的成员变量 name System.out.println(LocalInnerClassTest.this.name); // 在局部内部类中调用外部类的实例方法 run() LocalInnerClassTest.this.run(); // 在局部内部类中调用外部类的静态方法 go() LocalInnerClassTest.go(); } } // 创建局部内部类的实例 LocalInnerClass lic = new LocalInnerClass(); // 修改局部内部类的成员变量 name lic.name = "tom"; // 调用局部内部类的方法 test(),传入参数 "test" lic.test("test"); } public static void main(String[] args) { LocalInnerClassTest inner=new LocalInnerClassTest("wang",22); inner.test(); } } out: test tom xxx wang
注:局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。
5.4 匿名内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 定义一个接口 interface Greeting { void greet(); } public class AnonymousInnerClassExample { public static void main(String[] args) { // 使用匿名内部类创建实现 Greeting 接口并调用greet方法 new Greeting() { @Override public void greet() { System.out.println("Hello, world!"); } }.greet(); } }