Java常用类

文章目录

一、内部类

概念

在一个类的内部再定义一个完整的类,一般内部类和外部类都会有依赖(层次)关系

//外部类 身体
class Body{
    //内部类 头
    class Head{}
}
特点

1.编译之后可生成独立的字节码文件。

上述代码在编译之后,除了生成一个Body.class文件,还会生成一个内部类文件Body$Head.class

2.内部类可以直接访问外部类的私有成员,而不破外封装性

class Body{   
    private int headNum=1;
    class Head{
        public void show() {
            //直接访问,没有问题
			System.out.println(headNum);
		}
    }
}

3.可为外部类提供必要的内部功能组件。

比如Head作为Body的“组件”

分类

在这里插入图片描述
成员内部类、静态内部类、局部内部类、匿名内部类

1.成员内部类

特点
(1)在类的内部定义的,与实例变量、实例方法同级别的类。
(2)作为外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象

定义外部类、内部类

public class Outer {
    //成员变量
    private String name = "李四";
    private int age = 20;
    private String address = "上海";
    private String phone = "119";
    //内部类前面也可以加修饰符,与成员变量一样
    class Inner {
        private String address = "北京";
        private String phone = "120";    
        //方法
        public void show() {
            System.out.println(name);//外部类变量
            System.out.println(age);
            System.out.println(address);//内部类变量
            System.out.println(phone);
        }
    }
}

创建实例对象

public static void main(String[] args) {
	//创建外部类实例对象
    Outer outer = new Outer();
    //创建内部类实例对象
    Outer.Inner inner = outer.new Inner();
    //合在一起可以写成 Out.Inner inner = new Outer().new Inner();
    inner.show();
}
(3)当外部类、内部类存在同名属性时,会优先访问内部类属性,就近原则

那么如何在Inner内部类中访问外部类的同名属性呢?

//内部类调用外部类的同名属性
System.out.println(Outer.this.address);
//内部类调用内部类的属性也可以写成
System.out.println(this.address);
(4)成员内部类不能定义静态成员

特例:可以包含final修饰的静态常量

2.静态内部类

特点
(1)在成员内部类的基础之上添加一个static关键字,就变成了静态内部类
(2)不依赖外部对象,可直接创建或通过类名访问,可声明静态成员

其实静态内部类就相当于一个外部类,放在外部类中是为了增强外部类的功能,

只有内部类了才可以用static修饰,外部类不可以

静态内部类想要访问外部类属性,需要先创建外部类的对象

public class Outer {
    //成员变量
    private String name = "李四";
    private int age = 20;
    //内部类
    static class Inner {
        private String address = "北京";
        private String phone = "120";
        //方法
        public void show() {
            //调用外部类属性,先创建外部类对象
            Outer outer = new Outer();
            System.out.println(outer.name);//外部类变量
            System.out.println(outer.age);
            System.out.println(this.address);//内部类变量
            System.out.println(phone);
        }
    }
}
public static void main(String[] args) {
//直接创建静态内部类实例对象
    Outer.Inner inner = new Outer.Inner();
    inner.show();
}

这里的new Outer.Inner()中并没有创建Outer的对象,只是为了展示其包含关系,类名后面加()才是通过构造创建了对象

3.局部内部类

特点
(1)类似局部变量,定义在外部类方法中;作用范围和创建对象范围仅限于当前方法
public class Outer {
    //成员变量
    private String name = "李四";
    private int age = 20;
    //成员方法
    public void show() {
        //局部变量
        String address = "上海";
        //局部内部类
        class Inner{
            //局部内部类属性
            private String phone = "100";
            //局部内部类方法
            public void show2() {
                //可以访问外部类的变量
                System.out.println(phone);
            }
        }
        //创建局部内部类对象
        Inner inner = new Inner();
        inner.show2();
    }
}

如果成员方法show()为静态时,其内部类Inner就无法直接访问外部类的资源,需要创建外部类对象

必须在成员方法show()中创建内部类的对象inner,才能调用内部类中方法show2()

(2)局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final,当然,这个变量也无法再被修改
public void show2() {
	//可以访问外部类的变量
    System.out.println(phone);
    //访问外部类中的变量,必须确保外部变量为final
    System.out.println(address);
}

这里内部类中的方法show2()添加调用外部类方法show()中的局部变量address,正常情况下,外部方法show使用完局部变量address之后,变量就会消失,

但是内部类还需要引用address,需要address长期存在,所以必须把变量改为final修饰,这样内部类对这个常量的引用将不再指向address,而是直接引用常量

在jdk1.7时,必须手动添加addressfinal修饰,1.8之后,只要我们引用了,就会自动加上final修饰

(3)局部内部类中不能加静态成员,但是static前面再加上final变成常量就可以了

实际开发当中,局部内部类使用的不多

4.匿名内部类【重点】

特点
(1)没有类名的局部内部类(一切特征都与局部内部类相同)

实际上只是我们定义的时候没有取名字罢了,编译器编译之后会自动取一个名字

(2)必须继承一个父类或者实现一个接口

这不仅是使用的要求,这也是一般情况下使用匿名内部类的目的,因为我们使用匿名内部类就是为了方便创建实例,并调用其中的方法

正常情况下,我们这样使用

/**
 * 准备一个接口
 */
public interface USB {
	void work();
}
/**
 * 一个实现接口的类
 */
public class Mouse implements USB{
	@Override
	public void work() {
		System.out.println("鼠标正在工作。");
	}
}
//在另一个类中实例化上面的类,并调用其中的方法
public class testUSB {
	public static void main(String[] args) {
		USB usb=new Mouse();
		usb.work();
	}	
}

这是正常情况下我们新建一个实现类,可以让我们在不同类中多次使用。但是如果某个实现类只需要用到一次,之后就不会再用了,如果还是单独建一个class来实现的话是否麻烦且多余了?这时候就可以简化成局部内部类

public class testUSB {
	public static void main(String[] args) {
		//创建局部内部类
		class Phone implements USB{
			@Override
			public void work() {
				System.out.println("手机已连接。");			
			}			
		}
		//实例化
		Phone phone=new Phone();
		phone.work();
	}
}

因为实现类只使用一次,类名看起来也是多余的,那么再精简优化一下就变成了匿名内部类

也可以理解为直接把USB接口实例化了,虽然接口无法创建对象

public class testUSB {
	public static void main(String[] args) {
        //在new的接口中实现方法,这里也可以是一个抽象方法或者一个父类
		USB phone=new USB() {
			@Override
			public void work() {
				System.out.println("手机已连接。");		
			}			
		};
		phone.work();
	}
}
(3)它是定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
(4)优点是减少代码量,缺点是可读性差

我们可以查看一下本地生成的class文件,发现会一个testUSB$1.class文件,这个1就可以理解是匿名内部类的名字

二、Object类

特点
(1)超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
(2)任何类,如果没写extends关键字继承某个类,那么默认的就是直接继承Object类。
(3)Object类中所定义的方法,是所有对象都具备的方法。
(4)Object类型可以存储任何对象

作为参数,可接受任何对象。

作为返回值,可返回任何对象

方法
getClass()
public final Class<?> getClass(){...}

返回引用中存储的实际对象类型。

应用:通常用于判断两个引用中实际存储对象类型是否一致

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 class TestClass2 {
    public static void main(String[] args) {
        Student s1 = new Student("a",20);
        Student s2 = new Student("b",21);
        //判断student1和studen2是否同一个类
        if (s1==s2) {
            System.out.println("s1和s2是同一个类型");//输出结果
        } else {
            System.out.println("s1和s2不是同一个类型");
        }
    }
}
hashCode()
pubilc int hashCode(){...}

返回该对象的哈希码值

哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值

一般情况下相同对象返回相同哈希码

toString()
public String toString(){...}

返回该对象的字符串表示(表现形式)。

默认返回的是类名和一个十六进制表示的哈希值,也就是
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())。

可以根据程序需求覆盖/重写该方法,如展示对象的各个属性值

上面的s1对象如果使用toString打印结果和直接打印s1没有区别

public class TestClass2 {
    public static void main(String[] args) {
        Student s1 = new Student("a",20);
        System.out.println(s1.toString());
    }
}

得到Student类的全名+@+s1的哈希值,和和
在这里插入图片描述
查看toString源码

public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

实际上我们更希望看到这个对象的属性,所以通常我们会重写toString()方法,可以直接IDE工具生成,右键-gengerate-toString()

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}
equals()
public boolean equals(Object obj){...}

默认实现为(this==obj),比较两个对象地址是否相同。

可进行重写,比较两个对象的内容是否相同

面试常考equals和==的区别

重写equals()一般固有的步骤:

1.比较两个引用是否指向同一个对象。
2.判断obj是否为null。
3.判断两个引用指向的实际对象类型是否一致。
4.强制类型转换。
5.依次比较各个属性值是否相同。

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return this.age == student.age && this.name == student.name;
}
finalize()

当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列

什么是垃圾对象?

1.垃圾对象
没有有效引用指向此对象时,为垃圾对象

2.垃圾回收
由GC销毁垃圾对象,释放数据存储空间

3.自动回收机制
JVM的内存耗尽,一次性回收所有垃圾对象

4.手动回收机制
使用System.gc();通知JVM执行垃圾回收

这个方法实际上是不包含任何代码,它是一个空的方法,你可以重写该方法来观察JVM是否回收了某些对象,比如添加打印输出

protected void finalize() throws Throwable { }

重写,如果该方法执行了, 说明垃圾被回收了

@Override
protected void finalize() throws Throwable {
    System.out.println("垃圾被回收");
}

三、包装类

概念

基本数据类型所对应的引用数据类型

Object可统一所有数据,包装的默认值为nul

为了能让基本类型能功能更强大,将基本类型变为引用类型,他们就具备了属性和方法,基本类型数据存在栈中,变为引用类型后就可以存放在堆里了

基本数据类型 包装类型 对应关系

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter
类型转换与装箱、拆箱

每个基本类型都对应着一个引用(包装)类型,基本类型存储在栈空间而引用类型存储在堆空间;把基础类型转换成引用类型的过程叫做装箱,每个引用类型都提供了一些方法和属性可供使用;把引用类型转换成基础类型的过程叫做拆箱。

其中Byte Short Integer Long Float Double 都继承了父类Number

拆箱

Number中有byteValue() shortValue() intValue() longValue() doubleValue() floatValue() 可以将引用类型转为基本类型,这个过程叫拆箱

装箱
/**
 * 拆箱和装箱演示
 */
public class Demo1 {
	public static void main(String[] args) {
		//装箱(两种方法)
		int num1=10;
		Integer integer1=new Integer(num1);
		Integer integer2=Integer.valueOf(num1);	
		//拆箱
		int num2=integer1.intValue();
	}
}

在JDK1.5之前,我们需要进行如上的操作来装箱和拆箱,但在JDK1.5之后,java就提供了自动装箱和拆箱的功能,直接赋值

public static void main(String[] args) {
    //装箱
    int num1=10;
    Integer integer1=num1;
    //拆箱
    int num2=integer1;		
}

不必调用方法传值便可以实现装箱和拆箱。但实际上并不是不需要写,而是编译的时候java自动帮你做了这些工作。我们可以使用一个小工具Xjad来验证一下,这是一个反编译的工具,可以把class文件反编译成java代码,如果有需要可以自己百度下,这里只简单描述一下。运行上一段代码,将编译的class文件拖到这个小工具中,可以看到:

public static void main(String args[])
{
    int num1 = 10;
    Integer integer1 = Integer.valueOf(num1);
    int num2 = integer1.intValue();
}
字符串、基本类型之间转换

8种包装类提供不同类型间的转换方式。

Number父类中提供的6个共性方法。

parseXXX()静态方法。

valueOf()静态方法。

public class Demo2 {
	//基本类型和字符串之间的转换
	public static void main(String[] args) {
		//1.基本类型转换成字符串
		int n1=255;
		//1.1 使用+号
		String s1=n1+"";
		//1.2 使用Integer中的tostring方法
		String s3=Integer.toString(n1);
		String s2=Integer.toString(n1, 10);//第二个参数是基数,可以理解为x进制
		
		//2.字符串转换成基本类型
		String string="150";
		int n2=Integer.parseInt(string);
		
		//字符串转换成boolean类型,"true"->"true"  "非true"->"false"
		String string2="true";
		String string3="123";
		boolean b1=Boolean.parseBoolean(string2);//true
		boolean b2=Boolean.parseBoolean(string3);//false
	}
}
整数缓冲区

Java预先创建了256个常用的整数包装类型对象

public class Demo2 {
	public static void main(String[] args) {
		//返回false
		Integer integer1=new Integer(100);
		Integer integer2=new Integer(100);
		System.out.println(integer1==integer2);
		//返回true
		Integer integer3=100;
		Integer integer4=100;
		System.out.println(integer3==integer4);
		//返回false
		Integer integer5=200;
		Integer integer6=200;
		System.out.println(integer5==integer6);
	}
}

第一个,两个存储在栈空间的变量分别指向的是两个堆空间中的对象,两个对象的地址不一样,所以在比较时返回了false

第二个、第三个都是进行了自动装箱,但是结果不一样,首先清楚,自动装箱其实底层调用了valueOf()方法而不是构造方法,通过上面的反编译工具可以看到,

我们再查看valueOf()源码

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

进入到IntegerCache中

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

结论:Integer缓冲区是一个-127~128的数组cache = new Integer[(high - low) + 1];
果我们valueOf()里面的数值在缓存范围内,将直接返回缓存数组中的包装类对象

所以第二个返回的是缓存内的对象,第三个返回的是新创建的两个对象

这么设计是因为这些数在开发时常用,创建缓冲区可以提高效率

四、String类

特点
第一种创建方式

字符串是常量,创建之后不可变

字符串字面值存储在字符串池中,可以共享

public static void main(String[] args) {
        String name = "hello";
        name = "zhangsan";
        String name2 = "zhangsan";
    }

第一个name创建,在常量池中存入hello,然后指向name引用

第二name,在常量池中创建zhangsan,name指向新的常量,并没有修改原来的hello

第三个name2,创建时发现常量池中有zhangsan,所以也直接指向常量zhangsan
在这里插入图片描述
所以修改字符串其实是在常量池中重新开辟空间

第二种字符串创建方式
String str = new String("java");

这种方式,既创建了常量,也创建了对象,栈内存中的str指向堆中的对象,对象又指向了常量

所以这种创建方式也浪费了空间
在这里插入图片描述
如果我们又创建了对象str2

String str2 = new String("java");

str2指向了一个新的对象,新的对象又指向了同一个常量
在这里插入图片描述

字符串的equals和==【重点】

结论:

1.当我们直接用字符串赋值给变量时,如果字符串字面值相同,则变量==返回true,因为两个变量都指向同一个常量

public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1==s2);//返回true
    }

2.当我们用new String的方式创建字符串并赋值给变量时,两个变量==将返回false,因为他们指向了堆内存中不同的对象

public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1==s2);//返回false
    }

3.所以,当我们比较两个字符串的时候,推荐使用equals,因为String内部重写了equals方法,比较的是字面值,==比较则不一定,要看字符串的创建方式

public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1.equals(s2));//返回true
    }
常用方法

返回字符串长度

public int length()

根据下标获取字符串

public char charAt(int index)

判断当前字符串是否包含str

public boolean contains(String str)

将字符串转为数组

public char[] toCharArray()

查找str首次出现的下标,存在则返回下标,不存在则返回-1

public int indexOf(String str)

查找字符串在当前字符串中最后一次出现的下标索引

public int lastIndexOf(String str)

去掉字符串前后空格,不包含中间的

public String trim();

将小写转为大写

public String toUpperCase()

判断字符串是否以str结尾

public boolean endsWith(String str)

判断字符串是否以str开头

public boolean startsWith(String prefix)

旧字符串替换为新的字符串

public String replace(char oldChar, char newChar)

根据str做拆分

public String[] split(String regex)

忽略大小写比较

public boolean equalsIgnoreCase(String anotherString)

compare()比较两个字符串在编码表里面的位置,只比较第一个字符的编码大小

如果前面的字符串都一样,但是另一个字符串有更多的字符,则比较二者长度

返回的是编码值的差值,或者长度差

public int compareTo(String anotherString)
案例演示

需求:

已知String str = “this a text”;

1.将str中的单词单独获取

2.将str中的text替换为practice

3.在text前面插入一个easy

4.将每个单词的首字母改为大写

public class TestString {
    public static void main(String[] args) {
        String str = "this a text";
        String[] arr = str.split(" ");
        for (String s : arr) {
            System.out.println(s);
        }
        String str2 = str.replace("text", "practice");
        System.out.println(str2);
        str.replace("text", "easy text");
        System.out.println(str);
        for (int i=0;i< arr.length;i++) {
            char first = arr[i].charAt(0);
            char upperFirst = Character.toUpperCase(first);
            String str3 = upperFirst+arr[i].substring(1);
            System.out.println(str3);
        }
    }
}

五、可变字符串 StringBuffer StringBuilder

特点

String的特性决定了我们在使用时可能会产生大量的垃圾数据,效率比较低,

Sun公司开发了两个新的类,相当于String的增强类,效率更高,方法也更加强大

这两个类相当于String的增强类,事先开辟了一块缓冲区;这两个类的用法是一样的,效率都比String高

StringBuffer:可变长字符串,JDK1.0提供,运行效率慢、线程安全。
StringBuilder:可变长字符串,JDK1.5提供,运行效率快、线程不安全

演示
/**
 * 演示StringBuilder常用方法的使用
 * 效率比String高;比String节省内存
 */
public class Demo1 {
	public static void main(String[] args) {
		StringBuilder stringBuilder=new StringBuilder();
		//1. append();追加
		stringBuilder.append("我");//我
		stringBuilder.append("菜");//我菜
		//2. insert();插入
		stringBuilder.insert(0, "前");//前我菜
		//3. replace();替换
		stringBuilder.replace(1, 2, "你");//前你菜
		//4. delete();删除
		stringBuilder.delete(0, 1);//你菜
		System.out.println(stringBuilder.toString());
	}
}

上面注意含头不含尾

六、BigDecimal类

特点
double b1=1.0;
double b2=0.9;
System.out.print(b1-b2);

以上结果输出并不是0.1,而程序输出的结果是0.0999…98。因为浮点类型存储的实际是一个近似值,经过计算之后肯定会有误差,只不过这种误差很小

很多实际应用中需要精确计算,用double肯定不符合要求,这时候需要借助BigDecimal类来实现

演示
/**
 * 演示BigDecimal类的使用
 */
public class Demo1 {
	public static void main(String[] args) {
		BigDecimal b1=new BigDecimal("1.0");
		BigDecimal b2=new BigDecimal("0.9");
		System.out.println(b1.subtract(b2));//减法 0.1
		System.out.println(b1.add(b2));//加法 1.9
		System.out.println(b1.multiply(b2));//乘法 0.90	
        System.out.println(b2.divide(b1));//除法 0.9
	}
}
注意

1.传参的时候使用字符串

2.如果除法的结果除不尽,那么就会报一个异常;所以在除法运算的时候需要使用divide的另外一个重载方法divide(divisor, scale, roundingMode)

参数divisor:除数

参数scale:指定精确到小数点后几位

参数roundingMode:指定小数部分的取舍模式,通常采用四舍五入的模式。取值为BigDecimal.ROUND_HALF_UP

七、Date类

特点

Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代(已过时)

演示

创建时用util包的,不要使用sql包的

/**
 * 演示Date类中尚未过时的方法
 */
public class Demo1 {
	public static void main(String[] args) {
		Date d1=new Date();
		Date d2=new Date();
		//当前时间 Wed Nov 04 12:01:52 CST 2020
		System.out.println(d1.toString());
		//已过时,打印当地时间
		//2020-11-4 12:01:52
		System.out.println(d1.toLocaleString());
		
		//after before判断两个时间前后关系
		d2=new Date(d1.getTime()-60*60*24*1000);//昨天此刻
		System.out.println(d1.after(d2));//true 今天在昨天后面
		System.out.println(d1.before(d2));//false
		
		//compareTo比较,两者毫秒数相减,返回正负0
		System.out.println(d1.compareTo(d2));//1
		System.out.println(d2.compareTo(d1));//-1
		System.out.println(d1.compareTo(d1));//0
		
		//equals判断是否相等
		System.out.println(d1.equals(d2));//false
	}
}

八、Calendar类

特点

Calendar提供了获取或设置各种日历字段的方法

方法

构造方法protected Calendar()

由于修饰符是protected,所以无法直接创建该对象,而是使用static Calendar getInstance(),表示使用默认时区和区域获取日历

void set(int year,int month,int date,int hourOfDay,int minute,int second)

设置日历的年、月、日、时、分、秒。

int get(int field)

返回给定日历字段的值。字段比如年、月、日等。

void setTime(Date date)

用给定的Date设置次日历的时间。Date->Calendar

Date getTime()

返回一个Date表示此日历的时间。Calendar->Date

void add(int field,int amount)

按照日历的规则,给指定字段添加或减少时间量。

long getTimeMillies()

毫秒为单位返回该日历的时间值。

/**
 * 演示Calendar类常用方法的使用
 */
public class Demo2 {
	public static void main(String[] args) {
		//创建Calendar对象
		Calendar calendar=Calendar.getInstance();
		//2020-11-4 13:50:56
		System.out.println(calendar.getTime().toLocaleString());
		//1604469056368
		System.out.println(calendar.getTimeInMillis());
		
		//获取时间信息
		//年 2020
		System.out.println(calendar.get(Calendar.YEAR));
		//月 11 值为0-11
		System.out.println(calendar.get(Calendar.MONTH)+1);
		//日 4
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		//小时 1/13 12小时/24小时
		System.out.println(calendar.get(Calendar.HOUR));
		System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
		//分钟 50
		System.out.println(calendar.get(Calendar.MINUTE));
		//秒 56
		System.out.println(calendar.get(Calendar.SECOND));
		
		//修改时间
		calendar.set(Calendar.YEAR, 2019);
		//2019-11-4 13:50:56
		System.out.println(calendar.getTime().toLocaleString());
		
		//添加或减少时间量
		calendar.add(Calendar.MONTH, -1);
		//2019-10-4 13:50:56
		System.out.println(calendar.getTime().toLocaleString());
		
		//获取时间字段的最大值、最小值
		//31 / 1
		System.out.println(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		System.out.println(calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
	}
}

九、SimpleDateFormat类

特点

SimpleDateFormat是一个以语言环境有关的方式来格式化和解析日期的具体类。

可以进行格式化(日期到文本)和解析(文本和日期)。

常用的时间模式字母:

字母日期或时间
y
M年中月份
d月中天数
H1天中小时数0-23
m分钟
s
S毫秒
public class Demo3 {
	public static void main(String[] args) throws ParseException {
		//创建对象
		SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		//创建Date对象
		Date date=new Date();
		
		//格式化
		String string=simpleDateFormat.format(date);
		//2020/11/04 14:10:21
		System.out.println(string);
		
		//解析(必须按照上面格式化的形式)
		Date date2=simpleDateFormat.parse("1999/01/30 00:00:00");
		//1999-1-30 0:00:00
		System.out.println(date2.toLocaleString());
	}
}

十、System类

特点

系统类,主要用于获取系统的属性数据和其他操作,其构造方法是私有的。直接使用里面的静态方法

常用方法

static void arraycopy(...)

复制数组

static long currentTimeMillis()

获取当前系统时间,返回的是毫秒值。通常用来计算某个操作的用时,操作前后各获取一个时间然后相减,所得的毫秒数就是用时。

static void gc()

建议JVM赶快启动垃圾回收器回收垃圾,具体是否调用是由系统决定的。

static void exit(int status)

退出JVM,如果参数是0表示正常退出JVM,非0表示异常退出JVM。

/**
 * 演示arraycopy的使用
 */
public class Demo1 {
	public static void main(String[] args) {
		int[] src= {3,14,15,92,65,35,85};
		int[] dest = new int[7];
		int srcPos=0,destPos=0;
		int length=src.length;
		/**
		 * src:源数组
		 * scrPos:复制的源数组起始位置
		 * dest:目标数组
		 * destPos:复制的目标数组起始位置
		 * length:复制的数组长度
		 */
		System.arraycopy(src, srcPos, dest, destPos, length);
	}
}

在Arrays类里也有一个copyOf复制数组的方法,这两个方法有什么区别呢?通过查看源码发现Arrays的这个方法内部调用的就是System.arraycopy()方法,而arraycopy方法的源码是被native修饰的本地方法:

public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

可以看到方法体是空的,它是一个原生函数,并不是由java来实现的,而是由c/c++来实现的,java只是调用了它,由c++实现的这个方法效率会比java快很多

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值