从0开始复习java(4)--Class
oracle为java
提供了丰富的类库,java8提供了4000多个基础类。java程序员至少要熟悉java中70%的类。
一、交互
使用Scanner
获取键盘输入
Scanner是一个基于正则表达式的文本扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值。
Scanner主要提供了两个方法扫描输入:
- hasNextXxx():是否还有下一个输入项,其中Xxx可以是Int,Long等代表基本数据类型的字符串。
- nextXxx():获取下一个输入项。
import java.util.Scanner;
public class Test{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
//使用换行符作为分隔符
s.useDelimiter("\n");
while (s.hasNext()){
System.out.println(s.next());
}
}
}
默认情况下,Scanner使用空白(空格、tab、回车)作为多个输入项之间的分隔符。
Scanner读取文件输入:
import java.util.Scanner;
import java.io.File;
public class ScannerFileTest{
public static void main(String[] args) throws Exception{
Scanner s = new Scanner(new File("ScannerFileTest.java"));
while(s.hasNextLine()){
System.out.println(s.nextLine());
}
}
}
二、系统相关
java提供了System
和Runtime
类来与程序的运行平台进行交互。
1、System类
System类代表当前java程序的运行平台,不能创建对象,但是有类变量和类方法可以调用。
提供了代表标准输入、标准输出和错误输出的类变量,并提供一些静态方法访问环境变量、系统属性,还提供了加载文件和动态链接库的方法。
加载文件和动态链接库主要对
native
方法有用。如java不能访问操作系统底层设备,可以借助c语言完成。实现步骤如下:
1.java程序中声明native
修饰的方法,只有方法签名,没有实现,编译该Java文件,生成一个class
文件。
2.使用javah
编译第一步生成的class
文件,产生一个.h
文件。
3.写一个cpp
文件实现native
方法,需要包含第二步的文件(这个文件包含jdk带的jni.h
文件)
4.将第三步的cpp文件编译成动态链接库文件。
5.在Java中用System
类的loadLibrary()
方法或Runtime
类的loadLibrary()
方法加载第四步产生的动态链接库文件,Java程序中就可以调用这个native方法了。
import java.io.File;
import java.io.FileOutputStream;
import java.util.Map;
import java.util.Properties;
public class SystemTest{
public static void main(String[] args) throws Exception{
Map<String, String> env = System.getenv();
for(String s : env.keySet()){
System.out.println(s + "---->" +env.get(s));
}
System.out.println(System.getenv("JAVA_HOME"));
Properties pro = System.getProperties();
pro.store(new FileOutputStream(new File("properties.txt")), "System Properties");
System.out.println(System.getProperty("os.name"));
}
}
System类还提供了通知系统进行垃圾回收的gc()方法,以及通知系统进行资源清理的runFinalization()方法。
System类还有两个获取系统当前时间的方法:currentTimeMillis()
和nanoTime()
,他们返回一个long
类型的整数。这个两个方法返回的时间粒度取决于底层操作系统,可能所在的操作系统不支持以毫秒、纳秒作为计时单位。
System类的in、out、err分别代表系统的标准输入(通常是键盘)、标准输出(通常是显示器)和错误输出流,并提供了setIn()
、setOut()
、setErr()
方法修改。
System类还提供了一个identityHashCode(Object obj)
方法,该方法返回指定对象的精确hashCode值,也就是根据对象的地址计算的hashCode。当某个类的hashCode()
方法被重写后,该类实例的hashCode()方法不能唯一的标识该对象;但通过该方法依然是根据地址计算的hashCode值。
public class IdentifyHashCode{
public static void main(String[] args) {
String s1 = new String("123");
String s2 = new String("123");
//String类重写了hashCode方法,根据字符串序列计算hashCode值
//由于s1和s2序列相同,故其值相同
System.out.println(s1.hashCode()+"-----"+s2.hashCode());
System.out.println(System.identityHashCode(s1)+"-----"+System.identityHashCode(s2));
String s3 = "123";
String s4 = "123";
System.out.println(System.identityHashCode(s3)+"-----"+System.identityHashCode(s4));
}
}
2、Runtime类
Runtime类代表Java程序的运行时环境,每个java程序都有一个与之对应的Runtime
实例,应用程序通过该对象与其运行时环境相连。应用程序不能创建自己的Runtime
实例,但可以通过getRuntime()
方法获取与之相关的对象。
与System
相似,该类也提供了gc()
和runFinalization()
方法,并提供load(String filename)
和loadLibrary(String libname)
方法加载文件和动态链接库。
Runtime
类代表java运行时环境,可以访问jvm的相关信息。如处理器数量,内存信息。
public class RuntimeTest{
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println(rt.availableProcessors()+""+rt.freeMemory()+rt.totalMemory()+rt.maxMemory());
}
}
public class RuntimeTest{
public static void main(String[] args) throws Exception{
Runtime rt = Runtime.getRuntime();
rt.exec("notepad.exe");
}
}
Runtime可以直接单独启动一个进程来运行操作系统的命令。
3、常用类
Object类
所有的java类都是Object类的子类。
object类提供了如下常用方法:
boolean equals(Object obj)
判断对象与该对象是否相等。
protected void finalize()
当系统中没有引用变量引用到该对象时,垃圾回收期调用该方法清理该对象的资源。
Class<?> getClass()
返回该对象的运行时类
int hashCode()
返回该对象的hashcode值,默认通过地址计算。
String toString()
返回该对象的字符串表示。"运行时类名@十六进制hashCode"
wait()
notify()
notifyAll()
控制线程的暂停和运行。
protected clone()
帮助对象实现"自我克隆",即得到对象的副本。
自定义类实现克隆的方法:
- 实现
Cloneable
接口。标记型接口,没有任何方法。 - 实现自己的
clone()
方法。 - 实现
clone()
方法时通过super.clone()
调用Object
类的clone()
方法得到该对象的副本,并返回该副本。
class Address{
String detail;
public Address(String detail){
this.detail = detail;
}
}
class User implements Cloneable{
int age;
Address address;
public User(int age){
this.age = age;
}
public User clone() throws CloneNotSupportedException{
return (User)super.clone();
}
}
public class CloneTest{
public static void main(String[] args) throws CloneNotSupportedException{
User u1 = new User(20);
User u2 = u1.clone();
//false
System.out.println(u1==u2);
//true
System.out.println(u1.address==u2.address);
}
}
Object类的clone()方法是浅克隆,只是克隆了对象的所有成员变量值,不会对引用类型变量值所引用的对象进行克隆。
java7新增了一个Objects工具类,这些工具类是"空指针"安全的。如调用一个引用值为null
的引用变量的toString()
方法,将会引发NullPointerException
,但使用Objects.toString(Object o)
方法会返回null
。
import java.util.Objects;
public class ObjectsTest{
//null
static ObjectsTest obj;
public static void main(String[] args) {
System.out.println(Objects.hashCode(obj));
System.out.println(Objects.toString(obj));
System.out.println(Objects.requireNonNull(obj, "obj参数不能是null!"));
}
}
public Foo(Bar bar){
//如果bar为null,抛出NullPointerException,不为null时返回参数本身。
this.bar = Objects.requireNonNull(bar);
}
String、StringBuffer和StringBuilder类
Java提供了String
和StringBuffer
封装字符串。
String
是不可变类。
StringBuffer
对象代表一个字符序列可变的字符串。通过StringBuffer
提供的append()
,insert()
,reverse()
,setCharAt()
,setLength()
等方法修改字符串的字符序列,然后调用toString()
方法转换成字符串对象。
java5新增StringBuilder
类,和StringBuffer
类基本相似。StringBuffer
是线程安全的,StringBuilder
性能更高。通常情况下,优先考虑使用StringBuilder
。
String和StringBuffer、StringBuilder都实现了
CharSequence
接口,该接口可以认为是字符串的协议接口。
String类的方法:
- char charAt(int index)
- int compareTo(String anotherString)
返回第一个不相同字符的字符差,如果s1是s2的子串,
s1.compareTo(s2)
,则返回s1.length()-s2.length()。
- String concat(String str)
- boolean contentEquals(StringBuffer sb)
- static String copyValueOf(char[] data)
和
String(char[] content)
构造器功能相同。
- Static String copyValuesOf(char[] data, int offset, int count)
- boolean endsWith(String suffix)
- boolean equals(Object obj)
如果包含字符串相同,则返回true
- boolean equalsIgnoreCase(String str)
- byte[] getBytes()
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
- int indexOf()
- int lastIndexOf()
- int length()
- String replace(char oldChar, char newChar)
- boolean startsWith(String prefix)
- String subString(int beginIndex, int endIndex)
- char[] toCharArray()
- String toLowerCase()
- String toUpperCase()
- static String valueOf(X x)
StringBuffer
和StringBuilder
可以避免String
类会产生很多临时变量的问题,这两个类提供了length
和capacity
属性,length
包含字符序列的长度。capacity
一般比length
大。
Math类
ThreadLocalRandom与Random
Random专门生成伪随机数,有一个需要传入long
型整数的构造器。
ThreadLocalRandom是Java7新增的类,在并发访问的环境下可以减少多线程资源竞争,保证系统具有更好的线程安全性。与Random类的用法基本相似,提供了静态的current()
方法获取该类对象。
BigDecimal类
不建议使用BigDecimal(double val)
构造器,建议使用BigDecimal(String val)
构造器。提供了各种运算符方法进行基本运算。
不要使用
double
浮点数作为构造器参数来创建对象,可以使用静态方法BigDecimal.valueOf(double val)
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
4、Java8的日期、时间类
Java原本提供有Date
类和Calendar
类处理日期,但是Date
无法国际化,Calendar
过于复杂。
Date类
构造器Deprecated
的有4个,剩余两个:
- Date()
生成当前日期时间的Date对象。底层调用
System.currentTimeMillis()
- Date(long date)
根据long整型生成日期对象。参数表示和
GMT 1970.01.01 00:00:00
到该对象之间的时间差,以毫秒为单位。
除了Deprecated
的方法外,还有几个为数不多的方法:
- boolean after(Date when)
- boolean before(Date when)
- long getTime()
- void setTime(long time)
官方建议尽量少用
Date
类,需要对日期、时间进行加减运算,或者获取时间的年、月、日、时、分、秒,可以使用Calendar
类。
Calendar类
用于弥补Date
类的不足。它是一个抽象类,用于表示日历。
Java本身提供了一个GregorianCalendar
类,代表了通常所说的公历。
Calendar提供静态方法获取实例。Calendar.getInstance()
,可以根据TimeZone
、Locale
类获取特定的Calendar
,不指定则使用默认的。
Calendar和Date可以自由转换:
Calendar c = Calendar.getInstance();
Date d = c.getTime();
Calendar cc = Calendar.getInstance();
cc.setTime(d);
常用方法:
- void add(int field, int amount)
- int get(int field)
- int getActualMaximun(int field)
- int getActualMinimun(int field)
- void roll(int field, int amount)
- void set(int field, int value)
- void set(int year, int month, int date)
- void set(int year, int month, int date, int hourOfDay, int minute, int second)
filed
是Calendar类的类变量,如Calendar.YEAR
,Calendar.MONTH
等。
add和roll的却别
add用于改变Calendar的特点字段的值。有两条规则:
- 当被修改字段超过范围时,会发生进位
- 如果下一级字段也需要改变,则会修正到变化最小的值。
Calendar c = Calendar.getInstance();
c.set(2003,7,31,0,0,0);
//2003-07-31-->2004-02-29
c.add(MONTH, 6);
roll的规则与add不同,上一级字段不会增大,下一级字段和add相同。
设置Calendar
的容错性
Calendar c = Calendar.getInstance();
//关闭容错性
c.setLenient(false);
Calendar有两种解释日历的模式:lenient
模式和non-lenient
模式。
set方法延迟修改
使用set修改后,calendar所代表的时间不会立即修改,知道下次调用get(),getTime(),getTimeInmillis(),add()或roll()时才会重新计算日历时间。
Java8新增的日期、时间包
java.time
包下的类
- Clock
- Duration
- Instant
- LocalDate
- LocalTime
- LocalDateTime
- MonthDay
- Year
- YearMonth
- ZonedDateTime
- ZoneId
- DayOfWeek
- Month
Java8新增的日期、时间格式器
java.time.format
包下提供了一个DateTimeFormatter
格式器类。相当于java.text.DateFormat
和java.txt.SimpleDateFormat
的合体。