package InnerClass.demo01;
// 身体
public class Body {
// 头部 内部类也会生成class文件
class Header{
}
}
package InnerClass.demo01;
// 身体
public class Body {
private String name;
// 头部 内部类编译之后也会生成class字节码文件
class Header{
public void show() {
// 内部类可以直接访问外部类的私有成员,而不破坏封装。
System.out.println(name);
}
}
}
Outer.Inner inner = outer.new Inner();
Outer.Inner inner = new Outer().new Inner();
package InnerClass.demo02;
// 外部类
public class Outer {
// 实例变量 定义时可以在前面添加访问修饰符如private
private String name = "张三";
private int age = 20;
// 内部类 也可以在前面添加访问修饰符
class Inner{
private String address = "北京";
private String phone = "110";
// 内部类属性和外部类的属性名字相同:
private String name = "李四";
// 方法
public void show() {
// 打印外部类的属性
System.out.println(name);
// 打印外部类的属性,内部类属性和外部类的属性名字相同,Outer.this
System.out.println(Outer.this.name);
System.out.println(Outer.this.age);
// 打印内部类中的属性
System.out.println(this.address);
System.out.println(this.phone);
}
}
}
// 内部类中不能包含静态成员,会报错
private static String country = "中国";
// 但是可以包含静态常量
private static final String country = "中国";
package InnerClass.demo03;
// 外部类
public class Outer {
private String name = "李四";
private int age = 18;
// 静态内部类:和外部类相同级别
static class Inner{
private String address = "上海";
private String phone = "111";
// 静态成员
private static int count = 1000;
public void show() {
// 调用外部类的属性
// 1.先创建外部类对象
Outer outer = new Outer();
// 2.然后调用外部类对象的属性
System.out.println(outer.name);
System.out.println(outer.age);
// 调用静态内部类的属性和方法,直接调用
// 相当于调用自己的方法,属性名前面省略了this.
System.out.println(address);
System.out.println(this.phone);
// 调用静态内部类的静态属性,直接:类名.属性名
System.out.println(Inner.count);
}
}
}
package InnerClass.demo03;
public class TestOuter {
public static void main(String[] args) {
// 静态内部类就相当于外部类,所以直接创建静态内部类对象
Outer.Inner inner = new Outer.Inner(); // 此处只是表示包含关系
// 调用方法
inner.show();
}
}
定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final
限制的使用范围,局部内部类只能在当前方法中使用。
package InnerClass.demo04;
public class Outer {
private String name = "刘同学";
private int age = 21;
public void show() {
// 定义局部变量:肯定不能带访问修饰符~
String address = "江苏"; // 默认加上final 意味着后面不能对其进行修改
// 局部内部类:不能加任何访问修饰符
class Inner{
// 局部内部类的属性
private String phone = "1222222222";
private String email = "[email protected]";
// private static int count = 100; 会报错 局部内部类中是不能包含静态成员的
private final static int count = 100; //静态常量不会报错
public void show2() {
// 访问外部类的属性
// 相当于省略了Outer.this
System.out.println(name); // 如果show方法是静态的则要实例化外部类来访问其属性
System.out.println(Outer.this.age);
// 访问内部类的属性
// 相当于省略了this.
System.out.println(phone);
System.out.println(this.email);
// 访问局部变量,jdk1.7要求:变量必须是常量final,jdk1.8自动添加final
System.out.println(address); // 其实这里的address已经写死为常量 “江苏”
}
}
// 创建局部内部类对象
Inner inner = new Inner();
inner.show2();
}
}
package InnerClass.demo04;
public class TestOuter {
public static void main(String[] args) {
// 局部内部类只能在对应的方法内使用,所以要先创建外部类
Outer outer = new Outer();
outer.show();
}
}
没有类名的局部内部类(一切特征都与局部内部类相同)。
必须继承一个父类或者实现一个接口的情况下使用较多。
定义类、实现类、创建对象的语法合并、智能创建一个该类的对象。
优点:减少代码量。
缺点:可读性较差。
package InnerClass.demo05;
// 接口
public interface Usb {
// 服务
void service();
}
package InnerClass.demo05;
public class Mouse implements Usb {
@Override
public void service() {
System.out.println("连接电脑成功,鼠标开始工作!");
}
}
package InnerClass.demo05;
public class TestUsb {
public static void main(String[] args) {
// 创建接口类型的变量
/*Usb usb = new Mouse();
usb.service();*/
// 局部内部类
class Fan implements Usb {
@Override
public void service() {
System.out.println("连接电脑成功,风扇开始工作!");
}
}
// 使用局部内部类创建对象
// Usb usb = new Fan();
// usb.service();
// 使用匿名内部类优化(相当于创建了一个局部内部类)
// 匿名内部类的名字我们看不到,但是实际编译是有一个class文件的 叫做: TestUsb$1.class
Usb usb = new Usb() {
@Override
public void service() {
System.out.println("连接电脑成功,风扇开始工作!");
}
};
usb.service();
}
}
public final Class<?> getClass(){
}
package CommonClasses.demo01;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package CommonClasses.demo01;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa" , 20);
Student s2 = new Student("bbb" , 21);
// 判断s1和s2是不是同一个类型
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if (class1 == class2) {
System.out.println("s1和s2属于同一个类型");
} else {
System.out.println("s1和s2不是同一个类型");
}
}
}
结果:
s1和s2属于同一个类型
public int hashCode() {
}
返回该对象的哈希码值,
哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值。
一般情况下相同对象返回相同的哈希码,用hashCode()方法来判断两个对象是否是同一个对象。
package CommonClasses.demo01;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa" , 20);
Student s2 = new Student("bbb" , 21);
// hashCode方法
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3 = s1;
//s3和s1的hashCode值相同,指向的是同一个对象
System.out.println(s3.hashCode());
}
}
结果:
990368553
1096979270
990368553
public String toString() {
}
返回该对象的字符串表示(表现形式)。
可以根据程序需求覆盖该方法,如:展示对象各个属性值。
package CommonClasses.demo01;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa" , 20);
Student s2 = new Student("bbb" , 21);
// 3.toString方法
System.out.println(s1.toString());
System.out.println(s2.toString());
}
}
结果:
CommonClasses.demo01.Student@3b07d329
CommonClasses.demo01.Student@41629346
我们这里@后面的数字是hashCode但是和我们上面hashCode方法获得的值不一样,我们进入toString方法的源码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
可以看到源码部分将hashCode转为了16进制表示,hashCode得到的是十进制,二者实际上是一样的。
但有些时候,我们并不想看到原始的toString显示的东西,所以我们需要重写toString方法。
可以使用快捷键Alt + inert,也可以鼠标右键选择generate–>toString–>选中name和age属性即可。
package CommonClasses.demo01;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// public String toString() {
// return name + ";" + age;
// }
// 快捷键重写的toString方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
再次Run结果:
Student{name='aaa', age=20}
Student{name='bbb', age=21}
public boolean equals(Object obj) {
}
package CommonClasses.demo01;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa" , 20);
Student s2 = new Student("bbb" , 21);
// 4.equals方法:判断两个对象是否相等
// 比较的是地址
System.out.println(s1.equals(s2));
Student s4 = new Student("小明", 17);
Student s5 = new Student("小明", 17);
System.out.println(s4.equals(s5));
}
}
结果:
false
false
虽然新建了两个参数一样的Student对象s4和s5,但是equals方法返回的依然是false,说明equals方法是比较对象在堆中的地址的!
package CommonClasses.demo01;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// public String toString() {
// return name + ";" + age;
// }
// 快捷键重写的toString方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
// 1.判断两个对象是否是同一个引用
if (this == obj) {
return true;
}
// 2.判断obj是否为空
if(obj == null) {
return false;
}
// 3.判断是否是同一个类型
// if (this.getClass() == obj.getClass()) {
//
// }
// instanceof 判断对象是否是某种类型
if (obj instanceof Student) {
// 4.强制类型转换
Student s = (Student)obj;
// 5.比较属性
if (this.name.equals(s.getName()) && this.age == s.getAge()) {
return true;
}
}
return false;
}
}
此时我们再次运行得到结果为:
false
true
重写finalize()方法
package CommonClasses.demo01;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 重写finalize方法
@Override
protected void finalize() throws Throwable {
System.out.println(this.name + "对象被回收了");
}
}
提示:
包装类是基本数据类型所对应的引用数据类型。
八种四类的基本数据类型,这八种基本数据类型并没有什么可以直接使用的方法,除了用运算符做一些操作。而且基本数据类型是存放在栈中的,有了包装类之后,将存放在堆中,在栈中引用。
为了能对基本数据类型进行一些方法上的操作,Sun公司做了这些基本数据类型对应的引用数据类型,叫做基本数据类型的包装类,这样他们就拥有了属性和方法。
Object可以统一所有数据,包装类的默认值是null(引用数据类型的默认值)。
这八个基本数据类型对应的引用类型如下:
基本数据类型 | 包装类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
基本类型变量–>栈;引用类型变量–>堆。
装箱拆箱操作演示:
package CommonClasses.demo02;
public class Demo01 {
public static void main(String[] args) {
// int num = 10;
// 类型转换:装箱,基本类型转成引用类型的过程
// 基本类型
int num1 = 18;
// 使用Integer类创建对象
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
System.out.println("装箱");
System.out.println(integer1);
System.out.println(integer2);
// 类型转换:拆箱,引用类型转成基本类型
Integer integer3 = new Integer(100);
int num2 =integer3.intValue();
System.out.println("拆箱");
System.out.println(num2);
// 以上方式为JDK1.5之前的装箱拆箱操作
// JDK1.5后,提供自动装箱和拆箱
int age = 30;
// 自动装箱
Integer integer4 = age;
System.out.println("自动装箱");
System.out.println(integer4);
// 自动拆箱
int age2 = integer4;
System.out.println("自动拆箱");
System.out.println(age2);
}
}
如何实现的自动装箱拆箱?
在IDEA中查看class文件:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package CommonClasses.demo02;
public class Demo01 {
public Demo01() {
}
public static void main(String[] args) {
int num1 = 18;
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
System.out.println("装箱");
System.out.println(integer1);
System.out.println(integer2);
Integer integer3 = new Integer(100);
int num2 = integer3;
System.out.println("拆箱");
System.out.println(num2);
int age = 30;
Integer integer4 = Integer.valueOf(age);
System.out.println("自动装箱");
System.out.println(integer4);
int age2 = integer4;
System.out.println("自动拆箱");
System.out.println(age2);
}
}
可以发现其实是系统偷偷调用的Integer.valueOf();方法,不用我们手动操作了,实现了自动装箱拆箱操作。
基本类型和字符串之间的转换:
package CommonClasses.demo02;
public class Demo01 {
public static void main(String[] args) {
// int num = 10;
// 类型转换:装箱,基本类型转成引用类型的过程
// 基本类型
int num1 = 18;
// 使用Integer类创建对象
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
System.out.println("装箱");
System.out.println(integer1);
System.out.println(integer2);
// 类型转换:拆箱,引用类型转成基本类型
Integer integer3 = new Integer(100);
int num2 =integer3.intValue();
System.out.println("拆箱");
System.out.println(num2);
// 以上方式为JDK1.5之前的装箱拆箱操作
// JDK1.5后,提供自动装箱和拆箱
int age = 30;
// 自动装箱
Integer integer4 = age;
System.out.println("自动装箱");
System.out.println(integer4);
// 自动拆箱
int age2 = integer4;
System.out.println("自动拆箱");
System.out.println(age2);
System.out.println("===================");
// 基本类型和字符串之间的转换
// 1.基本类型转成字符串
int n1 = 100;
int n3 = 15;
// 1.1使用 + 号
String s1 = n1 + "";
// 1.2使用Integer.toString()方法
String s2 = Integer.toString(n1);
String s4 = Integer.toString(n3, 16); // 使用Integer重载方法转为指定进制
System.out.println(s1);
System.out.println(s2);
System.out.println("===================");
System.out.println(n3);
System.out.println(s4);
// 2.字符串转成基本类型
String str = "150"; // 这是字符串形式,如果这里不是数字,转换会报错:数字格式化错误
// 使用Integer.parseXXX()
int n2 = Integer.parseInt(str);
System.out.println(n2);
System.out.println("===================");
// boolean字符串形式转成基本类型:"true"--->true 不是"true"--->false
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
String str3 = "liu";
boolean b2 = Boolean.parseBoolean(str3);
System.out.println(b2);
}
}
package CommonClasses.demo02;
public class Demo02 {
public static void main(String[] args) {
// 面试题
Integer integer1 = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2); // false
Integer integer3 = 100; // 自动装箱 实际调用的Integer.valueof(100)
Integer integer4 = 100;
System.out.println(integer3 == integer4); // true
Integer integer5 = 200; // 自动装箱 实际调用的Integer.valueof(200)
Integer integer6 = 200;
System.out.println(integer5 == integer6); // false
}
}
结果:
false
true
false
原因:Java预先创建了256个常用的整数包装类型对象。在Integer.valueOf()方法源码中可以看到:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
static final int low = -128;
static final int high; // 127
static final Integer[] cache;
static Integer[] archivedCache;
发现有个IntegerCache,即Integer缓冲区 ,它的最小值low为-128 ,最大值high为127,Java预先创建了一个 high-low+1 = 256 长度的数组在堆空间中,保存的数字为-128~127之间的数。
integer3 和 integer4 在创建的时候只是从上边已经创建好的数组中取值为100的地址,所以两个引用取到的值都是数组中那个100,地址是相同的,返回true。
integer5 和 integer6 在数组中找的时候没有找到200,因为最大值为127,而源码中在数组中找不到的时候就会 new Integer(200),重新创建一个对象,在堆中的地址不同,返回false。
Integer valueOf(int i)的部分源码:
@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
字符串是常量,创建之后不可改变。
字符串字面值存储在字符串池(常量池)中,可以共享。(字符串池就在方法区中,不同jdk版本不同)。
学到这里,内存中至少有了:栈、堆、方法区。方法区在不同版本称呼不同,jdk1.8之后叫元空间,1.8之前叫永久代。
新建字符串的两种方式
package CommonClasses.demo02;
public class Demo03 {
public static void main(String[] args) {
// "hello" 常量存储在字符串池中。
String name = "hello";
// 在字符串池中又开辟一个空间,name指向zhangsan,hello若不用则会变成垃圾对象
// 给字符串赋值时,并没有修改数据,二是重新开辟一块空间
name = "zhangsan";
String name2 = "zhangsan";
// 字符串的另一种创建方式
String str = new String("Java是最好的编程语言");
String str2 = new String("Java是最好的编程语言");
System.out.println(str == str2); // false 比的是地址
// 在字符串中,equals先比较地址、地址不同则比较内容,最后返回true或者false
System.out.println(str.equals(str2)); // true 在这里比的是数据即字符串内容
}
}
结果:
false
true
在这里我们看equals的源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
可以看到在比较字符串时,是先比较的地址(==)是否相同,然后比较字符串中的值(内容)是否相同。
package CommonClasses.demo02;
import java.util.Arrays;
public class Demo03 {
public static void main(String[] args) {
// "hello" 常量存储在字符串池中。
String name = "hello";
// 在字符串池中又开辟一个空间,name指向zhangsan,hello若不用则会变成垃圾对象
// 给字符串赋值时,并没有修改数据,二是重新开辟一块空间
name = "zhangsan";
String name2 = "zhangsan";
// 字符串的另一种创建方式
String str = new String("Java是最好的编程语言");
String str2 = new String("Java是最好的编程语言");
System.out.println(str == str2); // false 比的是地址
// 在字符串中,equals先比较地址、地址不同则比较内容,最后返回true或者false
System.out.println(str.equals(str2)); // true 在这里比的是数据即字符串内容
System.out.println("======================");
// 字符串方法的使用
// 1.length();返回字符串的长度
// 2.charAt(int index);返回某个位置的字符
// 3.contains(String str);判断是否包含某个子字符串
String content = "Java是世界上最好的Java编程语言,Java真香"; // 空格也算一个字符
System.out.println(content.length());
System.out.println(content.charAt(0));
System.out.println(content.contains("Java"));
System.out.println(content.contains("php"));
System.out.println("======================");
// 字符串方法的使用
// 4.toCharArray();返回字符串对应的数组
// 5.indexOf();返回字符串首次出现的位置下标,不存在则返回-1
// 6.lastIndexOf();返回字符串最后一次出现的位置下标
System.out.println(Arrays.toString(content.toCharArray()));
System.out.println(content.indexOf("Java"));
// 从下角标为4的位置开始找
System.out.println(content.indexOf("Java", 4));
System.out.println(content.lastIndexOf("Java"));
System.out.println("======================");
// 字符串方法的使用
// 7.trim();去掉字符串前后的空格
// 8.toUpperCase();把小写转成大写、toLowerCase();把大写转成小写
// 9.endWith(str);判断是否以str结尾、startsWith(str)判断是否以str开头
String content2 = " Hello World ";
System.out.println(content2.trim());
System.out.println(content2.toUpperCase());
System.out.println(content2.toLowerCase());
String filename = "hello.java";
System.out.println(filename.endsWith(".java"));
System.out.println(filename.startsWith("hello"));
System.out.println("======================");
// 10.replace(char old, char new);用新的字符或字符串来替换旧的字符或字符串
// 11.split();对字符串进行拆分
System.out.println(content.replace("Java", "php"));
String say = "java is the best programing language,java xiang";
//中括号里有空格和逗号意思是同时按照这两个来拆分,+ 号表示空格或者逗号可以连续有好几个
String[] arr = say.split("[ ,]+");
// System.out.println(arr.length);
for (String string :
arr) {
System.out.println(string);
}
System.out.println("======================");
/*
补充两个方法equals、a.compareTo(b)
a.compareTo(b)按照字典顺序比较大小:相等返回0,
a > b 返回 a - b 的ASCII码值差值
a < b 返回 b - a 的ASCII码值差值
可以利用这一特性,返回值大于0则 a < b
返回值小于0则 a > b
返回值等于0则 a == b
*/
String s1 = "hello";
String s2 = "HELLO";
System.out.println(s1.equals(s2));
// 忽略大小写比较
System.out.println(s1.equalsIgnoreCase(s2));
String s3 = "abc"; // 97
String s4 = "xyz"; // 120
System.out.println(s3.compareTo(s4));
String s5 = "abc";
String s6 = "abcxyz";
System.out.println(s5.compareTo(s6));
String s7 = "abc";
String s8 = "abc";
System.out.println(s7.compareTo(s8));
System.out.println("======================");
// 还有个subString方法
String s9 = "Java is nice";
// 只有一个参数是提取从该位置(beginIndex)到最后的为新的子串
String s10 = s9.substring(5);
System.out.println(s10);
// 有两个参数则是提取从 beginIndex 到 endIndex 前为新的子串
String s11 = s9.substring(5, 7);
System.out.println(s11);
}
}
需求:
package CommonClasses.demo02;
public class Demo04 {
public static void main(String[] args) {
String str = "this is a text";
// 1.将str中的单词单独获取出来
String[] arr = str.split(" ");
for (String string :
arr) {
System.out.println(string);
}
System.out.println("===============");
// 2.将str中的text替换为practice
String str2 = str.replace("text", "practice");
System.out.println(str2);
System.out.println("===============");
// 3.在text前面插入一个easy
String str3 = str.replace("text", "easy text");
System.out.println(str3);
System.out.println("===============");
// 4.将每个单词的首字母改为大写
for (int i = 0; i < arr.length; i++) {
char first = arr[i].charAt(0);
// 把第一个字符转成大写
char upperFirst = Character.toUpperCase(first);
String newString = upperFirst + arr[i].substring(1);
System.out.print(newString + " ");
}
}
}
结果:
this
is
a
text
===============
this is a practice
===============
this is a easy text
===============
This Is A Text
由于String的不可变性,会产生大量垃圾,所以产生了String增强类,即开辟缓冲区,直接在缓冲区操作,提高字符串效率,也节省内存。
StringBuffer:可变长字符串,JDK1.0提供,运行效率慢,但是线程安全。
StringBuilder:可变长字符串,JDK5.0提供,运行效率快,但是线程不安全。(单线程推荐)
和String的区别:
下标原则:含头不含尾
package CommonClasses.demo02;
public class Demo05 {
public static void main(String[] args) {
// 单线程推荐使用 StringBuilder---> 效率高
// StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
// 1.append();追加
sb.append("Java世界第一");
System.out.println(sb.toString());
sb.append("Java真香");
System.out.println(sb.toString());
sb.append("Java真不错");
System.out.println(sb.toString());
// 2.insert();添加
sb.insert(0, "我在最前面");
System.out.println(sb.toString());
// 3.replace();可以指定位置的替换, 下标含头不含尾
sb.replace(0, 5, "现在我是第一");
System.out.println(sb.toString());
// 4.delete();可指定位置的删除
sb.delete(0, 6);
System.out.println(sb.toString());
// 5.reverse();反转
sb.reverse();
System.out.println(sb.toString());
// 6.清空sb字符串
sb.delete(0, sb.length());
System.out.println(sb.length());
if (sb.isEmpty()) {
System.out.println("sb字符串已清空");
}
}
}
结果:
Java世界第一
Java世界第一Java真香
Java世界第一Java真香Java真不错
我在最前面Java世界第一Java真香Java真不错
现在我是第一Java世界第一Java真香Java真不错
Java世界第一Java真香Java真不错
错不真avaJ香真avaJ一第界世avaJ
0
sb字符串已清空
验证 StringBuilder 的效率高于 StringBuffer:
package CommonClasses.demo02;
public class Demo06 {
public static void main(String[] args) {
// 开始时间
long start = System.currentTimeMillis();
String string = "";
// 用时:3111ms
// for (int i = 0; i < 99999; i++) {
// string += i;
// }
// System.out.println(string);
// 用时:22ms
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 99999; i++) {
sb.append(i);
}
System.out.println(sb.toString());
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - start));
}
}
可以看出,S和String比起来tringBuilder速度非常快。
package CommonClasses.demo02;
public class Demo07 {
public static void main(String[] args) {
double d1 = 1.0;
double d2 = 0.9;
System.out.println(d1 - d2);
}
}
结果:
0.09999999999999998
double 和 float 存的是近似值,是近似值存储,经过各种算数运算之后会出现误差
但特殊场景下不允许出现误差 ,因此需要借助BigDecimal类,它是一种精确存储。
位置:java.math包中。
作用:精确计算浮点数。
创建方式:BigDecimal bd = new BigDecimail(“1.0”);
方法:
加法:
BigDecimal add(BigDecimal bd);
减法:
BigDecimal subtract(BigDecimal bd);
乘法:
BigDecimal multiply(BigDecimal bd);
除法:
BigDecimal divide(BigDecimal bd);
结果除不尽的话 会报异常
所以除法用其他的构造方法:
divide(BigDecimal bd,int scal,RoundingMode mode);
package CommonClasses.demo02;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Demo07 {
public static void main(String[] args) {
double d1 = 1.0;
double d2 = 0.9;
System.out.println(d1 - d2);
// 面试题
double result = (1.4 - 0.5) / 0.9;
System.out.println(result);
// BigDecimal,大的浮点数的精确计算。
BigDecimal bd1 = new BigDecimal("1.0");//这里的构造方法一定要用字符串,因为字符串是最准确的
BigDecimal bd2 = new BigDecimal("0.9");
// 减法
BigDecimal r1 = bd1.subtract(bd2);
System.out.println(r1);
// 加法
BigDecimal r2 = bd1.add(bd2);
System.out.println(r2);
// 乘法
BigDecimal r3 = bd1.multiply(bd2);
System.out.println(r3);
// 除法
BigDecimal r4 = new BigDecimal("1.4").subtract(new BigDecimal("0.5")).divide(new BigDecimal("0.9"));
System.out.println(r4);
// 除不尽的情况
// BigDecimal r5 = new BigDecimal("20").divide(new BigDecimal("3"),2, BigDecimal.ROUND_HALF_UP);
// 上面的 BigDecimal.ROUND_HALF_UP 方法已经过时,但也可用
BigDecimal r5 = new BigDecimal("20").divide(new BigDecimal("3"),2, RoundingMode.HALF_UP);
System.out.println(r5);
}
}
很多都已经过时被替代了。
1970年是Unix操作系统元年。
package CommonClasses.demo03;
import java.util.Date;
public class Demo01 {
public static void main(String[] args) {
// 1.创建Date对象
Date date1 = new Date();
// 今天
System.out.println(date1.toString());
System.out.println(date1.toLocaleString());
// 昨天
Date date2 = new Date(date1.getTime() - (60 * 60 * 24 * 1000));
System.out.println(date2.toLocaleString());
// 2.方法 after(); before();
boolean b1 = date1.after(date2);
System.out.println(b1);
boolean b2 = date1.before(date2);
System.out.println(b2);
// 3.比较 compareTo();
int d = date1.compareTo(date2);
System.out.println(d);
int d1 = date2.compareTo(date1);
System.out.println(d1);
int d3 = date2.compareTo(date2);
System.out.println(d3);
// 4.比较是否相等equals();
boolean b3 = date1.equals(date2);
System.out.println(b3);
}
}
结果:
Fri May 26 13:21:41 HKT 2023
2023年5月26日 下午1:21:41
2023年5月25日 下午1:21:41
true
false
1
-1
0
false
Calendar提供了获取或设置各种日历字段的方法。
构造方法
其他方法
import java.util.Calendar;
public class Demo01 {
public static void main(String[] args) {
// 1.创建一个Calendar对象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toLocaleString());
System.out.println(calendar.getTimeInMillis()); // 1970年到现在的毫秒值
// 2.获取时间信息
// 获取年
int year = calendar.get(Calendar.YEAR);
//Calendar.YEAR == Calendar.1
// 3.获取月,月从 0-11
int month = calendar.get(Calendar.MONTH);
// 日
int day = calendar.get(Calendar.DAY_OF_MONTH); // Calendar.Date
// 小时
int hour = calendar.get(Calendar.HOUR_OF_DAY); // HOUR 12 小时制 ;HOUR_OF_DAY 24小时制
// 分钟
int minute = calendar.get(Calendar.MINUTE);
// 秒
int second = calendar.get(Calendar.SECOND);
System.out.println(year + “年” + (month + 1) + “月” + day + “日” + hour + “:” + minute + “:” + second);
// 修改时间
Calendar calendar2 = Calendar.getInstance();
// 日改成了昨天
calendar2.set(Calendar.DAY_OF_MONTH, 25);
System.out.println(calendar2.getTime().toLocaleString());
// 4.add法修改时间 增加1小时
calendar2.add(Calendar.HOUR, 1);
System.out.println(calendar2.getTime().toLocaleString());
// 减少2小时
calendar2.add(Calendar.HOUR, -2);
System.out.println(calendar2.getTime().toLocaleString());
// 5.补充方法
int max = calendar2.getActualMaximum(Calendar.DAY_OF_MONTH);//当前这个月的最大一天
int min = calendar2.getActualMinimum(Calendar.DAY_OF_MONTH);//当前这个月的最小一天
// 5月最大31天 最小1天
System.out.println(max);
System.out.println(min);
}
}
结果:
```java
2023年5月26日 下午3:19:14
1685085554360
2023年5月26日15:19:14
2023年5月25日 下午3:19:14
2023年5月25日 下午4:19:14
2023年5月25日 下午2:19:14
31
1
SimpleDateFormat是一个以与语言环境有关的方式格式化和解析日期的具体类。
进行格式化(日期 -> 文本)、解析(文本 -> 日期)。
常用的时间模式字母:
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo03 {
public static void main(String[] args) throws Exception {
// 1.创建SimpleDateFormat对象
// y–年 M–月
// 格式可变
// SimpleDateFormat sdf = new SimpleDateFormat(“yyyy年MM月dd日HH:mm:ss”);
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy/MM/dd”);
// 2.创建Date
Date date = new Date();
// 格式化date(把日期转成字符串)
String str = sdf.format(date);
System.out.println(str);
// 解析(把字符串转成日期) 格式与上面定义的格式不一样会报错
Date date2 = sdf.parse(“1990/05/26”);
System.out.println(date2);
}
}
结果:
```java
2023/05/26
Sat May 26 00:00:00 HKT 1990
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h3m2J6xg-1685107262345)(https://luck1y7.oss-cn-nanjing.aliyuncs.com/%E5%9B%BE%E5%BA%8A/image-20230526153741308.png)]
package CommonClasses.demo03;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected void finalize() throws Throwable {
System.out.println("回收了" + name + " " + age);
}
}
package CommonClasses.demo03;
public class Demo05 {
public static void main(String[] args) {
// 1.arraycopy,数组的复制
// src:原数组
// srcPos:从哪个位置开始复制,第一个位置为0
// dest:目标数组
// destPos:目标数组的位置
// length:复制的长度
int[] arr = {20, 18, 15, 8, 35, 26, 45, 90};
int[] dest = new int[8];
System.arraycopy(arr, 0, dest, 0, arr.length);
for (int i = 0; i < dest.length; i++) {
System.out.print(dest[i] + " ");
}
System.out.println();
// Arrays.copyOf(); 其实这个方法也是使用的System.arraycopy,效率很高
// 2.获取时间
System.out.println(System.currentTimeMillis());
// System.currentTimeMillis()方法实现计时
long start = System.currentTimeMillis();
for (int i = -99999999; i < 99999999; i++) {
for (int j = -99999999; j < 99999999; j++) {
int result = i + j;
}
}
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - start));
new Student("aaa", 19);
new Student("bbb", 19);
new Student("ccc", 19);
// 3.System.gc(); 告诉垃圾回收器回收垃圾
System.gc();
// 4.退出JVM
System.exit(0); // 后面的代码不会再执行了
System.out.println("程序结束了");
}
}
" " + age);
}
}
```java
package CommonClasses.demo03;
public class Demo05 {
public static void main(String[] args) {
// 1.arraycopy,数组的复制
// src:原数组
// srcPos:从哪个位置开始复制,第一个位置为0
// dest:目标数组
// destPos:目标数组的位置
// length:复制的长度
int[] arr = {20, 18, 15, 8, 35, 26, 45, 90};
int[] dest = new int[8];
System.arraycopy(arr, 0, dest, 0, arr.length);
for (int i = 0; i < dest.length; i++) {
System.out.print(dest[i] + " ");
}
System.out.println();
// Arrays.copyOf(); 其实这个方法也是使用的System.arraycopy,效率很高
// 2.获取时间
System.out.println(System.currentTimeMillis());
// System.currentTimeMillis()方法实现计时
long start = System.currentTimeMillis();
for (int i = -99999999; i < 99999999; i++) {
for (int j = -99999999; j < 99999999; j++) {
int result = i + j;
}
}
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - start));
new Student("aaa", 19);
new Student("bbb", 19);
new Student("ccc", 19);
// 3.System.gc(); 告诉垃圾回收器回收垃圾
System.gc();
// 4.退出JVM
System.exit(0); // 后面的代码不会再执行了
System.out.println("程序结束了");
}
}