Java学习笔记-Day21 Java System类、Class类、内部类
一、System类
System类(java.lang.System)包含几个有用的类字段和方法。 它不能被实例化。
1、System类提供的属性
static PrintStream err
:“标准”错误输出流,输出颜色为红色的数据。
System.err.println("red information");
static PrintStream out
:“标准”输出流,输出数据。
System.out.println("information");
static InputStream in
:“标准”输入流。
Scanner sc = new Scanner(System.in);
2、System类提供的静态方法
static long currentTimeMillis()
:返回当前时间(以毫秒为单位)。
long l = System.currentTimeMillis();//1604325938003
static long nanoTime()
:以纳秒为单位返回正在运行的Java虚拟机的高分辨率时间源的当前值。
long l = System.nanoTime();//1311210526165100
static void exit(int status)
:终止当前运行的Java虚拟机。
System.exit(0);
static void gc()
:运行垃圾回收器。
System.gc();
二、Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Java 的基本数据类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 表示为 Class 对象。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
1、获取Class类的对象
(1)调用 Class类的静态方法 forName,参数是 完整的包名+类名。
static 类<?> forName(String className)
:返回与给定字符串名称的类或接口相关联的 Class类的对象。
Class c = Class.forName("day19.Apple");
(2)通过 类名.class
,得到一个Class类的对象。
Class c = Apple.class;
(3)通过 对象.getClass()
,得到一个Class类的对象。
Apple a = new Apple();
Class c = a.getClass();
2、实例化Class类表示的对象
newInstance()
:创建由此Class类的对象表示的类的新实例。
Object obj = c.newInstance();
3、某个对象是否属于特定的类
通过使用关键字 instanceof 来判断某个对象是否属于特定的类。
if(obj instanceof Apple) {
Apple a = (Apple)obj;
}
4、根据用户的输入来创建某个类的对象
//根据用户的输入来创建某个类的对象
Scanner sc = new Scanner(System.in);
String name = sc.next();
Class c = Class.forName(name);
Object obj = c.newInstance();
if(obj instanceof Apple) {
Apple a = (Apple)obj;
a.showInfo();
}
三、内部类
内部类是在一个类的内部定义另一个类,内部类就成为外部类中的成员,访问权限修饰符可以是public、protected、default和private。
1、内部类的意义
(1)折中处理了类实现多继承。
//可以看作 类D 继承了 类A 和 类B
public class C extends A{
public class D extends B{
public void showA() {
showA();
}
@Override
public void showB() {
super.showB();
}
}
}
class B {
public void showB() {
System.out.println("b");
}
}
class A {
public void showA() {
System.out.println("a");
}
}
(2)形成闭包( 外部类中无法直接访问内部类中的成员,内部类中可以直接访问外部类的成员)。
public class OuterClass {
int i;
public void show1() {
System.out.println(i);
//System.out.println(j); 不能调用InnerClass中的变量j
}
public class InnerClass{
int j;
public void show2() {
System.out.println(i);//能调用InnerClass中的变量i
System.out.println(j);
}
}
}
2、内部类的分类
2.1、成员内部类
成员内部类是最普通的内部类。成员内部类是外部类的一个成员,可以无限制的访问外部类的所有成员属性和方法,包括 private 的。但是外部类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
2.1.1、定义成员内部类
成员内部类中不能存在任何static的变量和方法。
//外部类
class OuterClass {
int i;
public void show1() {
System.out.println(i);
}
//成员内部类
public class InnerClass{
int j;
public void show2() {
System.out.println(i);
System.out.println(j);
}
}
}
2.1.2、创建成员内部类对象
成员内部类是依附于外部类的,只有先创建了外部类才能够创建内部类。
(1)首先创建外部类对象。
(2)以 外部类.内部类
的形式进行声明。
(2)以 外部类对象.new 内部类构造方法()
的方式创建对象。
//创建外部类对象
OuterClass o = new OuterClass();
//外部类.内部类 对象名 = 外部类对象.new 内部类()
OuterClass.InnerClass i = o.new InnerClass();
2.2、局部内部类
局部内部类定义在了方法的内部,只能在该方法和作用域中被使用,出了该方法和作用域就会失效。
局部内部类可以直接访问或修改外部类的成员变量。
在局部内部类里访问方法中的变量(包括方法的参数)时,方法中的变量会默认是final(即使没有显式的用final修饰)。此时,如果对方法中的变量做修改操作,则与默认的final相矛盾,就会报错。
//外部类
public class OuterClass {
int a = 1;//外部类的变量,可进行修改
public void show() {
int b= 2;//默认为常量,不能进行修改
//局部内部类
class InnerClass{
int c = 3;//局部内部类的变量,可进行修改
public void show() {
++a;//编译通过
System.out.println(a);
//++b;编译不通过
System.out.println(b);
++c;//编译通过
System.out.println(c);
}
}
//在方法体中创建局部内部类对象
InnerClass i = new InnerClass();
i.show();
}
}
2.3、静态内部类
使用static修饰的内部类称为静态内部类。静态内部类与非静态内部类之间存在一个最大的区别,非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,但是静态内部类却没有。没有这个引用就意味着:
(1)它的创建是不需要依赖于外部类。
(2)它不能使用任何外部类的非static成员变量和方法。
(3)和成员内部类不同,static内部类能够声明static的成员。
2.3.1、定义静态内部类
//外部类
public class OuterClass {
static int a = 1;
//静态内部类
static class InnerClass{
int b= 1;
public void show() {
System.out.println(a);
System.out.println(b);
}
}
}
2.3.2、创建静态内部类对象
静态内部类创建对象时,不需要依赖外部类的对象。
//外部类.内部类 对象名 = new 外部类.内部类的构造方法();
OuterClass1.InnerClass1 i = new OuterClass1.InnerClass1();
2.4、匿名内部类
(1)匿名内部类是指不存在名字的内部类。
(2)匿名内部类必须继承一个父类或实现一个接口。
(3)匿名内部类没有构造方法,没有显式类名。
(4)匿名内部类对类的成员、方法的临时变量的访问规则和具备名字的内部类保持一致。
2.4.1、定义匿名内部类
注意:在大括号的后面有一个分号。
//外部类
public class TestOuterClass3 {
//匿名内部类
public OuterInterface i = new OuterInterface() {
int a = 123;
@Override
public void show() {
System.out.println(a);
}
};
public static void main(String[] args) {
TestOuterClass3 t = new TestOuterClass3();
t.i.show();
}
}
interface OuterInterface {
public void show();
}
3、内部类编译后的字节码文件
一旦内部类编译成功后,它就与外部类属于两个完全不同的类(虽然它们之间还是有联系的)。
//外部类
public class OuterClass{
//内部类
class InnerClass {
void show(){
System.out.println("InnerClass");
};
}
//接口
interface OuterInterface {
public void show();
}
//匿名内部类
public OuterInterface one = new OuterInterface() {
int num = 100;
@Override
public void show() {
System.out.println("OuterInterface one");
}
};
public OuterInterface two = new OuterInterface() {
int num = 200;
@Override
public void show() {
System.out.println("OuterInterface two");
}
};
public static void main(String[] args) {
OuterClass c = new OuterClass();
}
}
在编译成功后,会出现这样class文件:
外部类OuterClass: OuterClass.class
内部类InnerClass: OuterClass$InnerClass.class
接口OuterInterface:OuterClass$OuterInterface.class
第一个匿名内部类:OuterClass$1.class
第二个匿名内部类:OuterClass$2.class
四、Synchronized关键字
Synchronized(同步):实现线程安全、同步。可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时可以保证一个线程的变化可见。