单例模式
javaSE标准类中,java.lang.Runtime就是经典的单例模式。单例模式确保一个类中只有一个实例化对象产生。
构造器私有化,防止直接new,同时向外暴露一个静态的公共方法,用来返回单例对象。
饿汉式单例模式,类加载时实例化对象,如果没使用到这些对象,就会存在浪费资源的可能。 懒汉式单例模式,第一次使用时实例化。
饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
多例设计:一个类可以有多个实例化对象。
枚举
枚举也是基于多例设计的,但它更为简洁,使用enum关键字定义的的类默认会继承Enum抽象类,同时Enum还是一个final类。
枚举对象必须定义在首行.
使用无参构造器创建枚举对象,则实参列表和小括号都可以省略.
enum Theme {
RED,
BLUE,
GREEN;// 枚举对象必须在枚举类行首
private String title;
}
enum Color{
RED("红");
private String title;
Color(String title) {
this.title = title;
}
}
public class EnumDemo {
public static void main(String[] args) {
Theme val = Theme.RED;
switch (val){ //Switch支持枚举
case RED:
System.out.println("红色");
case BLUE:
System.out.println("蓝色");
case GREEN:
System.out.println("绿色");
}
for (Theme t: Theme.values()) {
System.out.println(t.ordinal() + ", " + t.name());
}
}
}
toString:Enum 类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息。
name:返回当前对象名(常量名),子类中不能重写.
ordinal:返回当前对象的位置号,默认从 0 开始.
values:返回当前枚举类中所有的常量.
valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!.
compareTo:比较两个枚举常量,比较的就是编号!
异常
它发生在程序运行期间,干扰了正常的指令流程。
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception。其中Error用来表示JVM无法处理的错误,Exception 分为两种:
- 受检异常 : 需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- 非受检异常 : 是程序运行时错误,例如除 0 会引发
Arithmetic Exception
,此时程序崩溃并且无法恢复。
常见运行时异常
程序的异常可以不做强制性处理
NullPointerException 空指针异常
ArithmeticException 数学运算异常
ArrayIndexOutOfBoundsException 数组下标越界异常
ClassCastException 类型转换异常
NumberFormatException 数字格式不正确异常
常见编译异常
是RuntimeException以外的异常,类型上都属于Exception类及其子类. IOException、SQLException等以及用户自定义的Exception异常.
异常捕获
try-catch-finally
异常发生,则异常发生后面的代码不会执行,直接进入catch块,异常没有发生,则顺序执行try的代码块,不会进入到catch.最后一定会执行finally里面的语句
不管是否发生异常,都执行(比如关闭连接,释放资源等),- finally {}
可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,(Exception 在后,NullPointerException 在前),如果发生异常,只会匹配一个catch。
try {
System.out.println("产生异常" + (1/0));
}catch (ArithmeticException e){
System.out.println(e);
System.out.print("获取完整异常信息");
e.printStackTrace();
}finally{
System.out.println("无论是否抛异常都执行");
}
throws异常处理
方法可能生成某种异常,但是并不确定如何处理,可以通过throws显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
对于编译异常,程序中必须处理,比如try-catch或者throws, 对于运行时异常,程序中如果没有处理,默认就是throws的方式处理.
重写方法时,子类重写的方法,所抛异常要么和父类异常一致,要么为父类抛出的异常类型的子类型。
public static void method() throws IOException, FileNotFoundException{
// ...
}
throw
在代码块中手动的抛出异常,而throws是在方法定义时,将程序可以出现的异常告知给调用者。
public static double method(int value) {
if(value == 0) {
throw new ArithmeticException("参数不能为0"); //抛出一个运行时异常
}
return 5.0 / value;
}
自定义异常
自定义异常类可继承Exception或RuntimeException
一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString方法会打印这些详细信息)
public class MyException extends Exception {
public MyException(){ }
public MyException(String msg){
super(msg);
}
// ...
}
assert断言
运行程序时需要加入-ea 参数
int x = 10;
x = x * 10;
assert x == 100;// 断言x
内部类
可以直接访问私有属性,并且可以体现类与类之间的包含关系
分类
- 定义在外部类局部位置上:
- 局部内部类(有类名)
- 匿名内部类(没有类名)
- 定义在外部类的成员位置上:
- 成员内部类(没有static修饰)
- 静态内部类(使用static修饰)
public class OuterDemo {
public static void main(String[] args) {
Outer o = new Outer();
//实例化静态内部类
Outer.StaticInner si = new Outer.StaticInner();
si.print();
// 内部接口
IConnect.connect((IConnect.IWay) new ConnectImpl());
new Outer().run(23893490);
}
}
class Outer{
static String name = "nangong";
private String msg = "外部类";
public void run(final long time){ // jdk1.8之前需要加final,方法内部类才能访问到方法的参数
class MethodInner{ // 方法内部类
public void print(){
System.out.println("方法内部类, " + Outer.name);
System.out.println(time);
}
}
new MethodInner().print();// 方法内部类直接实例化
}
class Inner{ //内部类
}
static class StaticInner{
// 静态内部类,只能访问static属性、方法
public void print(){
System.out.println(Outer.name);
}
}
}
interface IConnect{
public void send(String str);
static interface IWay{
public Boolean walk();
}
public static void connect(IWay way){
if(way.walk()){
System.out.println("连接");
}
}
}
class ConnectImpl implements IConnect.IWay {
public Boolean walk(){
return true;
}
}
局部内部类
局部内部类是定义在外部类的局部位置, 比如方法中,并且有类名。
不能添加访问修饰符。但是可以使用final修饰,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
匿名内部类
- 本质还是类,内部类,该类没有名字,同时还是一个对象.\
- 匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名\
- 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,可以调用匿名内部类方法。
- 可以直接访问外部类的所有成员,包含私有的。\
- 不能添加访问修饰符,因为它的地位就是一个局部变量。\
- 作用域:仅仅在定义它的方法或代码块中。\
- 匿名内部类—访向---->外部类成员[访问方式:直接访问]。\
- 外部其他类—不能访向---->匿名内部类(因为匿名内部类地位是一个局部变量)。\
- 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员) 去访问
//匿名内部类
IConnect ic = new IConnect() {
@Override
public void send(String str) {
System.out.println("匿名内部类: " + str);
}
};
ic.send("message");
Lamda表达式
函数式编程,简化代码 接口中只有函数式接口,才可以使用lamda表达式(有且只有一个抽象方法)
interface IMath{
public Integer add(int a, int b);
}
public class LamdaDemo {
public static void main(String[] args) {
IMath m = (a1, a2) -> {
return a1 + a2;
};
System.out.println(m.add(1, 4));
}
}
方法引用
interface IMath{
public Integer add(int a, int b);
}
//@FunctionalInterface //函数式接口
//interface IFunction<T>{
// public T change(int a);
//}
//@FunctionalInterface //函数式接口
//interface IFunction<T>{
// public T change();
//}
//@FunctionalInterface //函数式接口
//interface IFunction<T>{
// public int change(T t1, T t2);
//}
class TestLamda{
public TestLamda(String name, Integer age) {
this.name = name;
this.age = age;
}
private String name;
private Integer age;
}
@FunctionalInterface //函数式接口
interface IFunction<T>{
public T change(String a, int b);
}
public class LamdaDemo {
public static void main(String[] args) {
// 引用静态方法
// IFunction<String> i = String :: valueOf;
// String s = i.change(100);
// System.out.println(s.length());
//引用实例化对象操作方法
// IFunction<String> fun = "instance" :: toUpperCase;
// System.out.println(fun.change());
// 引用类中指定方法
// IFunction<String> method = String :: compareTo;
// System.out.println(method.change("A", "a"));
// 引用构造方法
IFunction<TestLamda> m1 = TestLamda :: new;
System.out.println(m1.change("A", 11));
}
}
内建函数式接口
功能型函数接口、消费型函数接口、供给型函数接口、断言型函数式接口
import java.util.function.*;
public class LamdaDemo {
public static void main(String[] args) {
Function<String,Boolean> f1 = "**test"::startsWith;
System.out.println(f1.apply("**"));
}
}