Java常用类(上)
运行Java程序的参数
main函数的方法签名,public static void main(String[] args){...}。
①public 因为它的调用者是虚拟机,所以要暴露出来。
②static因为JVM在调用这个方法时不会先去创建一个对象然后再去调用。
③void将一个值返回给JVM没有任何意义,JVM已经不会对返回值进行处理。
④谁调用函数谁就给这个函数的参数赋值。上面的字符串数组参数就是由JVM来赋值的。
怎样赋值?在命令行中可以比如说给一个ArgsTest类中的main参数赋值就应该写(在javac编译完成之后):java ArgsTest [参数值] 如果输入多个参数的话需要使用空格隔开。
Scanner文本扫描器
Scanner是一个基于正则表达式的文本扫描器。new Scanner(文档|输入流),平常所用到的System.in就是键盘输入。useDelimter(String pattern)方法设置分隔符。其中hasNext系列是判断是否有下一个(行)可读。nextXxx系列是获取到下一个(行)。
以下为示例代码分别为Scanner扫描输入流与文件:
package scannertest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;
public class ScannerFileTest {
public static void main(String[] args) throws FileNotFoundException {
FileReader fr = new FileReader(new File("prop.txt"));
Scanner sc = new Scanner(fr);
/*while(sc.hasNextLine()) {
System.out.println(sc.nextLine());
}*/
sc.useDelimiter("/n");//设置了分隔符格式
while(sc.hasNext()) {
System.out.println(sc.next());
}
System.out.println("\n\n\n\n\n\n\n\n");
Scanner sc1 = new Scanner(new File("prop.txt"));
/*while(sc.hasNextLine()) {
System.out.println(sc.nextLine());
}*/
sc1.useDelimiter("/n");//设置了分隔符格式,以换行符为分割
while(sc1.hasNext()) {
System.out.println(sc1.next());
}
}
}
System类
System类代表Java当前的运行平台,它提供了一些变量来访问系统的属性与环境变量等内容。以下代码将系统的环境变量读取到内存并且将获取到的系统的属性输出到一个文本文档中:
package systemtest;
import java.io.FileNotFoundException;
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(env.get("JAVA_HOME"));
/*Properties props = new Properties();
props.setProperty("hyl","主流7");
props.store(new FileOutputStream("props.txt"),"hyl");*/
Properties props = System.getProperties();
props.store(new FileOutputStream("prop.txt"),"This is a description message.");
System.out.println(System.getProperty("os.name"));
}
}
除此之外System类的identityHashCode(一个对象)可以唯一的确定这个对象的HashCode。而被重写过的hashCode()方法就不能唯一标识这个对象了。特别说明的就是相同序列的字符串常量(常量池中的字符串)它们的identityHashCode是相同的。代码如下:
package systemtest;
public class HashCodeTest {
public static void main(String[] args) {
String str1 = new String("hyl");
String str2 = new String("hyl");
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());//重写后的hash方法比较的只是序列是否相同
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));//真正意义上的比较是否为同一个对象
String str3 = "Java";
String str4 = "Java";
System.out.println(System.identityHashCode(str3));//相同的字符串,常量池
System.out.println(System.identityHashCode(str4));
}
}
当然还有垃圾回收机制的一些函数在这里就略了。
Runtime类
Runtime类是Java程序运行时的环境,每一个Java程序都对应有一个Runtime的实例,可以通过getRuntime()获取Runtime的实例。除了垃圾回收的相关方法,一下列举了几个其他的常用方法:
package runtimetest;
import java.io.IOException;
public class RuntimeTest {
public static void main(String[] args) throws IOException {
Runtime rt = Runtime.getRuntime();
System.out.println(rt.availableProcessors());//处理器数目
System.out.println(rt.maxMemory());//最大内存数
//调用操作系统中的API运行记事本程序
rt.exec("notepad.exe");
}
}
Object类与对象克隆
对象克隆的基本步骤:
①实现Cloneable这个标签接口
②自定义自己的克隆方法。
③自定义的克隆方法调用super.clone()方法来完成对象的克隆。
以下为对象克隆代码(克隆一个User对象):
package objecttest;
class Address{
String detail;
public Address(String addr) {
this.detail = detail;
}
}
class User implements Cloneable{
Address addr;
int age;
public User(int age) {
this.age = age;
addr = new Address("太原");
}
public User clone() throws CloneNotSupportedException {
return (User)super.clone();//调用Object的克隆方法来获得该对象的副本
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User(23);
User user2 = user1.clone();
System.out.println(user==user2);//它们不是同一个对象所以为false
System.out.println(user.addr == user2.addr);//完全相同的一个引用
}
}
当然这个克隆这是浅克隆没有完全的复制比如对象之中的引用类型的变量还是指向了同一个实例上面。下面为示意图:
Obgects的toString()静态方法有一个好处就是在传入的对象的参数为空的时候不会报异常而是会输出null。
String类系列
你所不知道的String类,他是一个不可变的字符串。比如说:
String str = "Java";
str = str1+"machinelearning";
str1 = str1 + "spark";
当执行完这三句话的时候就会产生5个字符串常量:”Java”,”machinelearning”,”spark”,
”Javamachinelearning”和”Javamachinelearningspark”而不是我们所想象的简单连接。
在newString(“hyl”)的时候内存中会有一个直接量”hyl”还会有一个对象newString(“hyl”)。
乱码杀手getBytes()方法
String类型的变量可以变换为二进制码的中间形式,而二进制码的数组又可以用不同的编码方式打开,从这一点来看当我们知道目标字符串的编码方式我们就可以用它的指定的编码方式打开从而解决乱码问题。将”中国”用gbk的方式打开。
String str = new String("中国");
byte[] b = str.getBytes();
String str1 = new String(b,"gbk");
System.out.println(str1);
String ss[] = {"123","345"};
字符串的比较compareTo方法,如果两个字符串长度不同但是前面的字符串相同的时候就返回这两个字符串的长度差,否则返回第一个不相同的字符差。代码如下:
String s = new String("asdfghjjl");
String s1 = new String("asdf");
String s2 = new String("asdfghjkl"); //第一个前面减去后面的字符差值
System.out.println(s.compareTo(s1)+" "+s.compareTo(s2));
//输出结果:5 -1
StringBuffer与StringBulider没什么可说的,只是StringBuffer能偶保障线程安全但是效率偏低,但是StringBulider不能够保证线程安全但是效率偏高。一般在没有线程安全的隐患下推荐用StringBulider。他们方法相似,在使用toString的时候变为一个定长的字符串。
计算机的精髓——随机数的产生
我们常常聊到的计算机随机数事实上是一个伪随机数,他是根据一个种子(可以理解为我们计算的源头)再加上一些复杂的计算最后得到一串看起来随机的数。由此我们知道如果种子一样再加上计算的算法一样我们就能够得到相同的伪随机数。
使用相同的种子相同的算法生成一个长度为16的数组
byte[] by = new byte[16];
Random r = new Random(50);//当使用默认种子创建Random对象时产生的是相同的结果
r.nextBytes(by);
System.out.println(Arrays.toString(by));
Random r1 = new Random(50);
r1.nextBytes(by);
System.out.println(Arrays.toString(by));
/*输出结果(前年不变)
[107, -125, -50, -70, -8, 115, 15, -103, -29, 116, 57, -99, 81, -20, 88, -46]
[107, -125, -50, -70, -8, 115, 15, -103, -29, 116, 57, -99, 81, -20, 88, -46]
*/
产生一个范围内的随机数
这个得益于Java7中的ThreadLocalRandom类,下面产生一个0到3的数。(在大多数编程语言中指明了几到几都是左闭右开的)。
Random r2 = new Random();
ThreadLocalRandom tr = ThreadLocalRandom.current();
int i = tr.nextInt(0,3);
System.out.println(i);
大数字计算克星BigDecimal
在一般的小数计算中往往会出现精度缺失的情况但是如果使用BigDecimal的valueof()话就不会出现这个问题。
package testBigDecimal;
import java.math.BigDecimal;
public class BigDecimalTest {
public static void main(String[] args) {
double b = 3.146312341234123412341234;
double b1 = 3.024712341234123412341234;
System.out.println(b+b1);//出现精度损失
BigDecimal bd = BigDecimal.valueOf(b);
BigDecimal bd1 = BigDecimal.valueOf(b1);
BigDecimal add = bd.add(bd1);
System.out.println(add);
}
}
/*输出
6.171024682468246
6.1710246824682468
*/
当然上面的valueof()也要求传入的是一个double型的小数对于超出8位的数还是不能计算。事实上BigDecimal中有一个基于String的构造器这个构造器能够计算任意长度的计算(理论上)。比如我让两个非常大的数相加:
package testBigDecimal;
import java.math.BigDecimal;
public class BigDecimalTest1 {
public static void main(String[] args) {
BigDecimal bd = new BigDecimal("3146312341234123411231231212341231231234");
BigDecimal bd1 = new BigDecimal("3024712341234123412121231231234123412312312");
BigDecimal add = bd.add(bd1);
System.out.println(add);
}
}
//输出略
关于时间
Date类就不说了,已经过气。
事实上Calendar类是一个非常强大的类,能够精确的表示多数时间。它有类似于Calendar.YEAR的静态变量通过静态变量与get()方法的组合可以获得分别当前的年月日时分秒。下面是一个获得当前时间的Calendar方法。而且在时间的加减计算方面也表现的非常智能。
package testCalendar;
import java.util.Calendar;
import java.util.Date;
public class CalendarTest {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH)+1;
int date = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
String h = hour < 10 ? "0" : "";
String m = minute < 10 ? "0" : "";
String s = second < 10 ? "0" : "";
String time = year+"年"+month+"月"+date+"日"+h+hour+":"+m+minute+":"+s+second;
System.out.println(time);
cal.set(year, month, date);
cal.add(Calendar.MONTH, 10);//时间的相加很智能
System.out.println(cal.get(Calendar.MONTH));
}
}
下面结合Timer与TimerTask方法定制一个电子时钟。先上图(虽然有点丑: -):
其中会用到一个TimerTask类它表示一个时间任务,任务体放在自己的run方法中。比如我们需要每隔重画钟表的屏幕,在这里我们使用了匿名内部类之所以不用lambda表达式是因为它不是一个函数式接口:
TimerTask timerTask = new TimerTask() {//他不是一个函数式接口,所以匿名内部类还是蛮有用的
@Override
public void run() {
clock.setText(getCurTime());
}
};
Timber类是一个调度线程的设备它可以控制TimberTask的运行情况,最简单的比如说延时调用t.schedule(timerTask, 1000)在1秒之后调用该任务。当然我们的时钟是没有延时的而且是每秒一次的调用t.schedule(timerTask, 0,1000)。时钟的具体代码如下:
package testCalendar;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CalendarTest1 extends JFrame{
public String getCurTime() {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH)+1;
int date = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
String h = hour < 10 ? "0" : "";
String m = minute < 10 ? "0" : "";
String s = second < 10 ? "0" : "";
String time = year+"年"+month+"月"+date+"日"+h+hour+":"+m+minute+":"+s+second;
return time;
}
public CalendarTest1() {
this.setTitle("zhuliu7");
this.setSize(300, 200);
JLabel clock = new JLabel();
TimerTask timerTask = new TimerTask() {//他不是一个函数式接口,所以匿名内部类还是蛮有用的
@Override
public void run() {
clock.setText(getCurTime());
}
};
Timer t = new Timer();
t.schedule(timerTask, 0,1000);
this.add(clock);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new CalendarTest1();
}
}
上一篇: 定时器的应用