Java笔记:与系统交互、系统相关的类,Object类
1.程序与用户交互
(1)运行一个Java程序的时候要给它提供一个main方法入口,这边分析一下这个main方法的签名
public static void main(String[] args);
public修饰符:因为Java类给JVM调用的,所以要使用public修饰符暴露这个方法
static修饰符:JVM调用主方法的时候不会先创建该主类的对象,而是直接通过该类来调用主方法的,所以使用static修饰。
void返回值:因为主方法是JVM调用的,所以该方法的返回值返回给JVM没有任何意义。
字符串数组形参:根据方法调用的规则,谁调用该方法,谁负责为形参赋值。所以是JVM赋值的,那到底是赋什么值呢,可以看下面一个例子
package cn.lsl; public class ArgsTest { public static void main(String[] args) { System.out.println(args.length); for(String arg : args){ System.out.println(arg); } } }
上面程序只是输出一个0,这说明args数组是一个长度为0的空数组。
而如果改成用命令来运行该程序
java ArgsTest aa bb
将输出
运行Java程序时在类名后紧跟一个或多个字符串,多个字符串之间用空格隔开,JVM就会把这些字符串依次赋值给args元素
如果一个参数本身包含空格,则这个参数应该用双引号括起来
(2)使用Scanner获取键盘输入
使用Scanner类可以很方便地获取用户的键盘输入
Scanner主要提供了两个方法用来扫描输入
1)hasNextXxx():是否还有下一个输入项,其中Xxx可以是Int、Long等代表基本数据类型的字符串。如果需要判断是否包含下一个字符串,则可以省略Xxx。
2)nextXxx():获取下一个输入项。Xxx的含义与前一个方法中的Xxx相同。
package cn.lsl; import java.util.Scanner; public class ScannerDemo { public static void main(String[] args) { //System.in代表标准输入,就是键盘输入 Scanner sc = new Scanner(System.in); //sc.useDelimiter("\n"); while(sc.hasNext()){ System.out.println("键盘输入的内容是:" + sc.next()); } } }
默认情况下,Scanner使用空白作为多个输入项之间的分隔符。如果希望改变Scanner的分隔符(不适用空白作为分隔符),
例如程序需要每次读取一行,不管这一行中是否包含空格,Scanner都把它当成一个输入项。这是可以使用sc.useDelimiter("\n");把Scanner的分隔符设置成回车符。
获取基本类型类型的输入项
package cn.lsl; import java.util.Scanner; public class ScannerLongDemo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNextLong()){ System.out.println("键盘输入内容为:" + sc.nextLong()); } } }
Scanner提供两个简单的方法来逐行读取
boolean hasNextLine():返回输入源中是否还有下一行
String nextLine():返回输入源中下一行的字符串
package cn.lsl; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class ScannerFileDemo { public static void main(String[] args) throws FileNotFoundException { Scanner sc = new Scanner(new File("src/cn/lsl/ScannerDemo.java")); System.out.println("ScannerDemo.java文件的内容如下:"); while(sc.hasNextLine()){ System.out.println(sc.nextLine()); } } }
使用BufferedReader获取键盘输入
1)BufferedReader是Java IO流中一个字符、包装流,它必须建立在另一个字符流的基础之上。但标准输入:System.in是字节流,程序需要使用转换流InputStreamReader将其包装成字符流。
2)获取了BufferedReader对象之后,可以调用该对象的readLine()方法来逐行读取键盘输入,每次用户的键盘输入都被BufferedReader当成String对象。与Scanner不同的是,BufferedReader不能读取基本类型输入项,它总是读取String对象。
package cn.lsl; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class BufferReaderDemo { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line = br.readLine())!=null){ System.out.println("键盘输入的是:" + line); } } }
2.System类
System类代表当前Java程序的运行平台,程序不能创建System类的对象。
一些方法:
getenv :
public static Map<String,String> getenv(),返回一个不能修改的当前系统环境的字符串映射视图
public static String getenv(String name),获取指定的环境变量值
public static Properties getProperties(),确定当前的系统属性
public static String getProperty(String key),获取指定键指示的系统属性
package cn.lsl; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; import java.util.Properties; public class SystemTest { public static void main(String[] args) throws FileNotFoundException, IOException { //获取系统的所有环境变量 Map<String, String> env = System.getenv(); for(String name : env.keySet()){ System.out.println(name + "----->" + env.get(name)); } System.out.println("-------------------------"); //获取指定环境变量的值 System.out.println(System.getenv("JAVA_HOME")); System.out.println("-------------------------"); //获取所有的系统属性 Properties props = System.getProperties(); //将所有系统属性保存到props.txt文件中 props.store(new FileOutputStream("props.txt"), "System Properties"); System.out.println(System.getProperty("os.name")); } }
上面程序通过System类的getenv()、getProperties()、getProperty等方法来访问程序所在平台的环境变量和系统属性。
public static int identityHashCode(Object x),该方法返回指定对象的精确hashCode值,也就是根据该对象的地址计算得到hashCode值。当某个类的hashCode()方法被重写以后,该类实例的hashCode()方法就不能唯一标识该对象,但是通过identityHashCode(Object x)方法返回的hashCode值,依然是根据该对象的地址计算得到的hashCode值。所以,两个对象的identityHashCode值相同,则两个对象绝对是同一个对象。
package cn.lsl; public class IdentityHashCodeTest { public static void main(String[] args) { String s1 = new String("Hello"); String s2 = new String("Hello"); System.out.println(s1.hashCode() + "----" + s2.hashCode()); System.out.println(System.identityHashCode(s1) + "------" + System.identityHashCode(s2)); String s3 = "java"; String s4 = "java"; System.out.println(System.identityHashCode(s3) + "------" + System.identityHashCode(s4)); } }
3.Runtime类
Runtime类代表Java程序的运行环境,每个Java程序都有一个与之对应的Runtime实例,应用程序通过该对象与其运行时环境相连。应用程序不能创建自己的Runtime实例,但可以通过getRuntime()方法获取与之关联的Runtime对象。
Runtime类代表Java程序的运行时环境,可以访问JVM的相关信息,如处理器数量,内存信息等
package cn.lsl; public class RuntimeDemo { public static void main(String[] args) { Runtime rt = Runtime.getRuntime(); System.out.println("处理器数量:" + rt.availableProcessors()); System.out.println("空闲内存数:" + rt.freeMemory()); System.out.println("总内存数:" + rt.totalMemory()); System.out.println("可用最大内存数:" + rt.maxMemory()); } }
Runtime类还可以直接单独启动一个进程来运行操作系统的命令。
package cn.lsl; import java.io.IOException; public class ExecTest { public static void main(String[] args) throws IOException { Runtime rt = Runtime.getRuntime(); rt.exec("notepad.exe"); } }
4.Object类
(1)Object类是所有类的父类,Java允许把任何类型的对象赋值给Object类型的变量。定义一个类的时候没有使用extends关键字显示指定他的父类,则该类默认继承Object父类。
(2)Java中提供一个protected修饰的clone()方法,该方法用于实现“克隆”,就是得到一个当前对象的副本,而且二者之间完全隔离。由于Object类提供的clone()方法使用了protected修饰,因此该方法只能被子类重写或调用。
自定义类实现克隆的步骤:
1.自定义类实现Cloneable接口。这是一个标记性的接口,接口里面没有定义任何方法。
2.自定义类实现自己clone()方法。
3.实现clone()方法时通过调用super.clone();调用Object实现clone()方法来得到该对象的副本,并返回该副本。
package cn.lsl; 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; address = new Address("福建"); } 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(); System.out.println(u1 == u2); System.out.println(u1.address == u2.address); } }
对象实现“克隆”的时候,克隆出来的对象是原对象的副本,所以System.out.println(u1 == u2);返回的是false;
Object类提供的Clone机制只对对象里各实例变量进行“简单复制”,如果实例变量的类型是引用类型,Clone机制也只是简单点的复制这个引用变量,这样原有对象的引用类型的实例与克隆对象的引用类型的实例变量依然指向内存中同一个实例,即System.out.println(u1.address == u2.address);返回true
(Object类的clone()方法只克隆该对象的所有Field值,不会对引用类型的Field所引用的对象进行克隆)
5.Objects类(Java 7 新增的)
Java 7 新增的Objects工具类,它提供了一些工具方法来操作对象,这些工具方法大多是“空指针”安全的。
package cn.lsl; import java.util.Objects; public class ObjectsTest { static ObjectsTest obj; public static void main(String[] args) { //输出一个null对象的hashCode值,输出0 System.out.println(Objects.hashCode(obj)); //输出一个null对象的toString,输出null System.out.println(Objects.toString(obj)); //要求obj不能为null,如果为null将引发空指针异常 System.out.println(Objects.requireNonNull(obj, "obj参数不能是null")); } }
requireNonNull()方法,传入参数不为null时,该方法返回参数本身;否则将引起空指针异常,该方法主要用来对方法形参进行输出校验,
例如:
public Foo(Bar bar){ //校验bar参数,如果bar参数为null将引发异常;否则this.bar被赋值为bar参数 this.bar = Objects.requireNonNull(bar); }