1.内部类
-
一般内部类
public class Pratice { public static void main(String[] args) { /* 内部类 : 描述事物内部的事物 ; 就是一个类定义在另一个类的内部 当内部类定义在成员变量的位置上时,可以被成员修饰符修饰,修饰后会具备修饰符的特征 1.private 只能在当前类中访问. 推荐 2.static 访问出现局限性. 此时如果要访问外部类的成员, 需要将外部成员也静态化 */ // 间接访问 : Outer outer = new Outer(); outer.function(); // 直接访问(了解) : // 不建议. 内部类一般有特有用途, 推荐通过外部类间接使用. 最好给内部类加上private修饰符 Outer.Inner inner = new Outer().new Inner(); inner.show(); } } public class Outer { private int num = 110; class Inner{// 最好加上private修饰符. 加static的话, 如果要访问num, 需要将num也静态化. public void show(){ // 内部类可以访问所在外部类的所有成员,包括私有成员在内 System.out.println("num = " + num); } } public void function(){ // 外部类要访问内部类,必须创建对象 Inner inner = new Inner(); inner.show(); } }
-
局部内部类
public class Pratice { public static void main(String[] args) { int x = 10; int y = 10; // 局部内部类 : 定义在局部位置的内部类,不能被成员修饰符修饰 // 被局部内部类使用的外部变量, 一开始就会自动变为final. // 原因是函数调用完就结束,类不行. 内部类和外部类没有区别. 但局部内部类用了函数的局部变量, 之后处理很复杂, 于是强制转final. // https://www.runoob.com/w3cnote/inner-lambda-final.html class Inner { public void show(int z) { System.out.println("inner show"); System.out.println("x = " + x); System.out.println("z = " + z); //x += 1;error z += 1; System.out.println("z = " + z); } } y = 11; Inner inner = new Inner(); inner.show(3306); inner.show(1521); inner.show(8080); } }
-
匿名内部类
public class Practice { public static void main(String[] args) { /* 匿名内部类 : 没有名字的内部类 本质 : 就是一个有点胖的匿名对象 格式 : new 父类/接口(){} ; */ Computer computer = new Computer(); computer.run(); // 听音乐 computer.function(new LoudspeakerBox());// 正常写法 computer.function(new USB(){// 匿名内部类, 不再额外创建一个类, 直接写类 @Override public void start() { System.out.println("摄像头开启"); } @Override public void close() { System.out.println("摄像头关闭"); } }); // lambda编程风格 : 面向函数 -> : lambda运算符 } } public class Computer { public void run(){ System.out.println("电脑开始运行了...."); } public void function(USB usb){ usb.start(); usb.close(); } } public interface USB { void start(); void close(); } public class LoudspeakerBox implements USB{ @Override public void start() { System.out.println("音箱启动"); } @Override public void close() { System.out.println("音箱关闭"); } }
2.Object类
-
Object类常用函数
public class Practice { public static void main(String[] args) throws ClassNotFoundException { /* Object类 : Object是类层次结构的根。 每个类都使用Object作为超类/父类/根类。 包括数组在内的所有对象都实现此类的方法 主要有以下函数,以及Practice02中的equals函数 */ // clone() // 创建并返回此对象的副本。 // void finalize() JDK9 过时的 , 不推荐使用 // GC 进行垃圾回收前会调用该函数 A a = new A(); a = null; System.gc();// 通知GC进行垃圾回收 // Class<?> getClass() // 返回此对象的运行时类。其实就是字节码文件的对象 // 获取字节码文件对象的三种方式 : // 1. Object : Class<?> getClass() a = new A(); Class<?> clazz1 = a.getClass(); System.out.println("clazz1 = " + clazz1); // <> : 泛型 // 2. 所有的类型都有一个静态的默认的属性 : .class Class<?> clazz2 = A.class; System.out.println("clazz2 = " + clazz2); System.out.println("int.class = " + int.class); System.out.println("void.class = " + void.class); System.out.println("---------------------------------"); // 3. Class : public static Class forName(String 全类名) Class<?> clazz3 = Class.forName("com.msr.lesson04.A"); System.out.println("clazz3 = " + clazz3); // int hashCode() // 返回对象的哈希代码值/地址值。 System.out.println(a.hashCode());// 10进制地址值 System.out.println("a = " + a);// 16进制地址值 System.out.println("----------------------------------------"); // String toString() // 返回对象的字符串表示形式。 System.out.println(a); System.out.println(a.toString()); Person person = new Person(); System.out.println(person); System.out.println(person.toString()); System.out.println(person.getClass().getName() + "@@" + Integer.toHexString(person.hashCode())); System.out.println(clazz1.getName()); // void notify() // 唤醒正在等待此对象的 监控。 // void notifyAll() // 唤醒在此对象的监视器上等待的所有线程。 // void wait() // 使当前线程等待,直到它被唤醒,通常 通过被通知或中断。 // void wait(long timeoutMillis) // 使当前线程等待,直到它被唤醒,通常 通过被通知或打断,或直到 一定数量的实时时间已经过去。 // void wait(long timeoutMillis, int nanos) } } public class Practice02 { public static void main(String[] args) { // boolean equals(Object obj) // 默认使用 == 进行比较, 只能比较地址值. 一般需要重写, 来比较内容是否一致 Person person1 = new Person("lisi", 20); Person person2 = new Person("lisi", 20); System.out.println(person1 == person2);// false System.out.println(person1.equals(person2));// 不重写比较地址值,就会报错 String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1 == s2);// System.out.println(s1.equals(s2));// String已经经过重写, 比较内容 // 枚举 : // 学生系统 // 常用类/Throwable } } public class A { @Override protected void finalize() throws Throwable { System.out.println("呀 被回收了...."); } } public class Person { private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } public boolean equalsByName(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(name, person.name); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) { return false; } Person person = (Person) o; return Objects.equals(name, person.name) && Objects.equals(age, person.age); } @Override public int hashCode() { return Objects.hash(name, age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
3.枚举
-
枚举
public class Practice { /* 枚举 : 是一个特殊的类 , 对象是有限个并且是不可变的(jdk5.0开始支持) 自带创建好的类对象数组, 通过类名直接访问, 不推荐创建类对象, 或修改类数组 */ public static void main(String[] args) { System.out.println(Season.AUTUMN); Season[] seasons = Season.values();// 拿到枚举对象(类数组) for (Season season : seasons) { System.out.println(season + " ------ " + season.getName() + " :: " + season.getDesc()); } System.out.println("---------------------------------"); Season season = Season.valueOf("SPRING");// 拿到指定的类变量 System.out.println("season = " + season); } } public enum Season { /* 除了enum声明, 和正常类写法基本一致 直接A,A()来创建对象 A是调用空参构造器,A()是调用相应的带参构造器 格式是A,B,C,D; 在最后一个对象前都是, 结尾;代表对象创建完了 */ SPRING("春天", "春风又绿江南岸"), SUMMER("夏天", "映日荷花别样红"), AUTUMN("秋天", "秋水共长天一色"), WINTER("冬天", "千里冰封,万里雪飘"); private String name; private String desc; // 枚举中的构造器都是私有 Season(String name, String desc) { this.name = name; this.desc = desc; } public String getName() {// 推荐只创建get函数 return name; } public String getDesc() { return desc; } @Override public String toString() { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } } public class Practice02 { public static void main(String[] args) { // Thread类 源码中的 1747 行 内部枚举类 // 线程的状态 : // Thread : Thread.State[] states = Thread.State.values(); for (Thread.State state : states) { System.out.println("state = " + state); } } }
4.异常
-
异常体系
public class Practice { public static void main(String[] args) { /* 异常体系 : Throwable : 是Java语言中所有错误和异常的超类 |Error/错误 : 过于严重,无法解决 |Exception/异常 : 可能出现的异常, 需要考虑解决方法 |RuntimeException/运行时异常 : 代码执行过程中才出现的异常 , 比如 NullPointerException |RuntimeException之外的异常/编译时异常 : 编译时期就会提示,比如 ClassNotFoundException 只有作为此类实例(或其子类之一)的对象才会由Java虚拟机抛出, 或者可以由Java抛出语句抛出。 类似地,只有这个类或它的一个子类可以是catch子句中的参数类型。 为了在编译时检查异常,Throwable和任何不属于RuntimeException或Error子类的Throwable子类都被视为已检查异常。 */ /* 异常处理基本格式 : try{ 可能发生异常的代码; }catch(异常类型 异常名){ 异常发生时的处理方式; }finally{ 一定要被执行的代码; } 注意 : 1.有异常但没有异常处理结构时 : 程序会终止在异常发生的那一行 2.有异常并且有对应异常处理结构时 : 程序在异常产生的位置开始跳转 ----> catch语句 ----> finally语句 ----> 程序正常运行 3.有异常并且有异常处理结构 , 但是没有对产生的异常进行处理时 : 程序在异常产生的位置开始跳转 ----> finally语句 ----> 程序打印异常信息 ----> 程序终止 4.有 处理方式 , 但没有异常产生 : try语句执行完后 --> finally语句 ---> 程序正常运行 finally语句都会执行,除非在这之前就被 System.exit(0); 命令给结束掉程序 finally 不是必须的, 内容常为内存释放, 比如 : scanner.close(); */ /* 多异常的处理时 try{ }catch(异常类型 异常名){ }catch(异常类型 异常名){ }........... finally{ } 当一个try对应多个catch语句时 , catch语句中的父类异常要写到后面 */ Demo demo = new Demo(); try{ int x = demo.div(10, 0); System.out.println("x = " + x); }catch (ArithmeticException | NoSuchElementException e){ System.out.println("除数不能为0"); }catch (NullPointerException e) { System.out.println("null指针 : 有变量为null 啦!!"); } catch (Exception e) { System.out.println("抓住老大!!"); }finally { System.out.println("finally 一定会被执行"); } System.out.println("over"); } } public class Demo { public int div(int a,int b){ return a / b; } }
-
throw及异常信息输出
public class Practice { public static void main(String[] args) { Demo demo = new Demo(); int x = 0; try { x = demo.div(10, 0); } catch (Exception e) { // String getMessage() : 获取异常产生的原因 System.out.println("e.getMessage() = " + e.getMessage()); System.out.println("-----------------------------------------------"); // String toString() : 异常名称 + 异常原因 System.out.println("e.toString() = " + e.toString()); System.out.println("-----------------------------------------------"); // void printStackTrace() : 打印异常的原因 , 异常名称 以及异常产生的位置 // 该方法也是 JVM 的默认处理方法 e.printStackTrace(); } System.out.println("x = " + x); System.out.println("over"); // https://zhuanlan.zhihu.com/p/558991703 // 总结参考 : https://blog.csdn.net/weixin_46756314/article/details/122360486 } } public class Demo { /* throw : 判定可能会出问题, 主动抛出一个异常 要求调用者必须使用try-catch语句, 处理可能出现的异常 这种情况下异常被处理, 不会打断程序运行. 如果抛出的是一个编译时异常,需要在函数部分进行声明 ; 如果抛出的是一个运行时异常,不需要在函数部分进行声明 ; throws : 名次 , 用于函数声明部分 , 声明异常 */ public int div(int a, int b) throws Exception { if (b == 0) { throw new Exception("除数不能为 0 !");// 输出异常信息 } return a / b; } }