史上最全讲解: JAVA中的单例模式,内部类与异常
文章目录
设计模式共有23种设计模式,是前辈对代码开发经验的总结.不仅仅Java,其它面向对象语言也有.
单例模式
单例模式是保证类只存在一个对象.实现方式主要有懒汉式与饿汉式.
懒汉模式
懒汉式:调用功能的时候才创建对象.
package com.shsxt.single02;
public class SingleLazy {
//1私有的静态的类属性
private static SingleLazy single = null;
//2.空构器私有
private SingleLazy(){
}
//3.公共的访问方式 公共的静态的上锁的返回值为SingleLazy的方法
public static synchronized SingleLazy getInstance() {
if(SingleLazy.single==null){
SingleLazy.single = new SingleLazy();
}
return SingleLazy.single;
}
}
饿汉模式
类第一次加载完成之后就创建对象.
package com.shsxt.single02;
//饿汉模式 线程安全
public class SingleHungry {
//类一加载完就创建对象
private static SingleHungry single = new SingleHungry();
//构造器私有
private SingleHungry(){
}
//公共的访问方式 静态方法 返回一个SingleHungry类型的对象single
public static SingleHungry getInstance (){
return single;
}
}
二者优缺点
懒汉式:线程不安全(多个线程操作同一份资源的时候 有可能会出现线程不安全)
饿汉式:线程安全
工厂模式
工厂去创建对象用户拿去用
代理模式
为其他对象提供一种代理以控制对这个对象的访问
- 注意:真实角色需要与代理角色实现相同的接口,代理需要持有真实角色的引用
- 好处:减少与真实角色的交流,提高代码的安全性,解耦,便于后期维护,代理角色可以扩展功能
- 实例: 项目经理与HR招聘的过程中,项目经理需要将部分功能交于HR
package com.shsxt.single01;
public class StaticPolxy {
public static void main(String[] args) {
Manager manager = new Manager();//招聘经理创建好了把地址值传给HR
//HR找到对应的地址值才可以.
HR hr = new HR(manager);
hr.recruit();
}
}
interface Recruitment{
public void recruit();
}
class Manager implements Recruitment{
@Override
public void recruit() {
System.out.println("录用");
}
}
class HR implements Recruitment{
Manager manager;//定义一个Manager类型的manager参数
//先有项目经理后有HR
//将manager定义为一个成员属性传给recruit方法
//也可以定义为recruit方法的一个参数传进来
//但是重写不可以 接口里的方法没有参数
public HR(Manager manager){
super();
this.manager = manager;
}
@Override
public void recruit() {
System.out.println("招聘");
manager.recruit();
//用到了Manager里的方法
}
}
内部类
类中定义的类,当一个类中的成员也是另外一个事务的时候(汽车的发动机,人的心脏器官),这个事务就可以使用内部类定义
成员内部类
- 定义:内部类处于外部类的成员位置,是外部类的成员就可以使用成员修饰符,是一个类就有类的特性,可以继承父类,可以实现接口.
- 注意:
1.内部类中可以使用外部类中的所有内容,包括私有的
2.静态内部类以外的其它内部类不可以定义静态的内容,除了静态的常量
3.外部类中使用内部类的成员,通过内部类的对象
public class Outer01 {
private int a=5; //成员变量
String haha="123";
//内部类
public class Inner extends A{
int b=3; //内部类中的成员变量
static final int c=10;
String haha="456";
public void inner(){
String haha="789";
System.out.println("我是内部类中的成员方法");
System.out.println(b);
System.out.println(a);
//局部haha
System.out.println(haha);
//内部类成员haha
System.out.println(this.haha);
//外部类成员haha
System.out.println(Outer01.this.haha);
}
}
//外部类中的成员方法
void outer(){
//内部类对象
Inner in=new Inner();
System.out.println(in.b);
}
}
class A{}
//另外一个java文件
package com.shsxt.inner03;
/*
* 内部类测试类
*/
public class Test {
public static void main(String[] args) {
//成员内部类依赖于外部类的对象使用
//创建成员内部类对象1
Outer01 out=new Outer01();
//Inner in=out.new Inner();
Outer01.Inner in=out.new Inner();
System.out.println(in.b);
in.inner();
//创建成员内部类对象2
Outer01.Inner in2=new Outer01().new Inner();
}
}
静态内部类
- 定义:成员内部类一旦被静态修饰符static修饰,就是静态内部类.
- 注意:
1.如果在外部类中使用静态内部类的成员,需要跟随内部类对象使用,如果使用静态内部类中的内容直接类名.调用
2.如果在静态内部类中使用外部的成员,都要跟随外部对象使用,如果使用静态内容,在内部类中可以直接使用
public class Outer02 {
private int a=5;
private static int b=10;
//静态内部类
static class Inner{
String name="zhangsan";
static int age=15;
void test1(){
System.out.println("内部类中的成员方法");
System.out.println(name);
System.out.println(age);
Outer02 out=new Outer02();
System.out.println(out.a);
System.out.println(b);
}
}
void outer(){
System.out.println(Inner.age);
Inner in=new Inner();
System.out.println(in.name);
in.test1();
}
}
私有内部类
- 定义:成员内部类一旦被私有修饰符private修饰就是私有内部类.
- 注意:
1.私有内部类只能在当前所定义的外部类中使用,其他类无法使用
2.在外部类中通过内部类的对象使用内部类的内容,保护私有内容
public class Outer03 {
private int a=5;
//私有内部类
private class Inner{
private int b=10;
void inner(){
System.out.println(a);
System.out.println(b);
}
}
void outer(){
Inner is=new Inner();
System.out.println(is.b);
}
}
局部内部类
- 定义:定义在一个类中的方法当中的类.局部内部类只能在当前定义的方法中使用,外部类中的其他方法无法使用局部内部类.
- 注意:
局部内部类中使用当前所在类中的参数时,参数默认被final修饰,在局部内部类中使用不能修改参数的值
public class Outer04 {
String name="lisi";
void test(int i){
//局部变量
int a=10;
//局部内不类
class Inner{
void inner(){
System.out.println(a);
System.out.println(name);
System.out.println(i);
}
}
//方法中通过内部类的对象使用成员
new Inner().inner();
}
void outer(){
//new Inner().inner();
}
}
匿名内部类
- 定义: 如果某个类单纯只是为了实现某个接口(重写某个抽象方法)的实现类.而本身没有自己的作用,这时候可以使用匿名内部类
package com.shsxt.inner03;
public class Anonymous {
public static void main(String[] args) {
//接口的匿名对象调用其中的一个方法
new Study(){
@Override
public void study() {
System.out.println("好好学习");
}
@Override
public void sleep() {
System.out.println("好好睡觉");
}
}.study();
//匿名对象调用很多方法
Study s = new Study(){
@Override
public void study() {
System.out.println("好好学习");
}
@Override
public void sleep() {
System.out.println("好好睡觉");
}
};
s.study();
s.sleep();
new Anonymous().test(new Study(){
@Override
public void study() {
System.out.println("好好学习");
}
@Override
public void sleep() {
System.out.println("好好睡觉");
}
});
new Anonymous().test(s);
}
void test(Study s){
s.study();
s.sleep();
}
}
interface Study{
void study();
void sleep();
}
Lambda表达式
- 作用:用来简化匿名内部类
- 前提:函数式接口(只有一个抽象方法的接口),修饰符@FunctionalInterface
- 语法格式:
() -> {}
()抽象方法的参数列表
->箭头函数或者参数列表,具有上下文推导的作用
{}抽象方法的方法题; - 注意:
1.lamdba表达式最全写法不要忘记{}后的分号
2.如果方法体只有一句,可以省略花括号{};
3.如果抽象方法有参数,参数类型可以省略
4,抽象方法的参数只有一个,()可以省略
5.如果与具体只有一句,是return的话,前后{}与return关键字可以一起省略
package com.shsxt.inner03;
public class Lambda04 {
public static void main(String[] args) {
new Sleep(){
@Override
public int sleep(int a) {
System.out.println("好好睡觉");
return 1;
}
}.sleep(1);
Sleep s= (a) -> {
System.out.println("好好睡觉");
return 1;
};
s = (a)->{System.out.println("好好睡觉");
return 1;};
Eat e = (a)-> 0;
System.out.println(e.eat(1));
}
}
@FunctionalInterface
interface Sleep{
int sleep(int a);
}
@FunctionalInterface
interface Eat{
int eat(int a);
}
异常Exception
在java中,异常与错误是两个不同的概念,throwable分为exception和error.错误error一般是由虚拟机产生的,不需要关注.异常分为编译异常和运行异常.throw制造异常, throw new NullPointerException();
编译异常 CheckedException
出现不处理程序无法执行,一般有两种处理方式
- throws抛出异常 把异常抛给上一层,谁用谁处理
- try…catch(){}捕获异常
格式:
try..catch(){}
* try{
* 可能会出现异常的代码
* }catch(FileNotFoundException e){
* 执行...
*
* }catch(NullpointerException e){
* 执行...
*
* }catch(Exception e){
* 接盘侠
* }
* ....
* fially{
* 无论是否会出现异常,都会执行的代码
* }
- 注意:
1.一个try后可以跟多个catch
2.如果try中的代码没有出现异常,正常执行完毕,执行finally中的内容结束
3.如果try中出现异常,下面的代码不会执行,直接进入对应的catch中
4.finally无论是否出现异常,都会执行的代码
public class ExceptionDemo02 {
public static void main(String[] args) {
try {
System.out.println("try开始了");
test();
System.out.println(5/0);
System.out.println("try结束了");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(ArithmeticException e){
System.out.println("出现数学异常了");
} catch(Exception e){
e.printStackTrace();
} finally{
System.out.println("最后的最后我们都会狗带...");
}
}
static void test() throws FileNotFoundException{
//对象是异常的形式出现
//throw new NullPointerException();
InputStream is=new FileInputStream("D:/test.txt");
}
}
常见的异常Exception
1.空指针异常
-
2.数组越界异常IndexOutOfBoundryException
-
3.数学异常 ArithmeticException
-
4.类型转换异常 ClassCastException
-
5.数组长度负数异常 NegativeArraySizeException
-
6.数学转换异常 NumberFormatException
-
7.空指针异常 NullPointerException
自定义异常
- 自定义异常类步骤
1.继承java.lang.Exception声明自己是异常类
2.方法的适当语句制造异常 throw
3.在方法声明部分用throws语句声明该方法可能抛出异常
4.调用该方法的时候用try catch语句捕获异常
自定义异常可以更好地提示发生的异常是什么,更加灵活! - 实例
package com.shsxt.definedexception;
public class DefinedException02 {
public static void main(String[] args) {
try {
Users users = new Users("111");
System.out.println(111222);
} catch (MyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
System.out.println("我是finally");
}
}
}
class Users {
//private String name;
private String password;
public String getPassword() {
return password;
}
public Users() {
super();
}
public Users(String password) throws MyException {
if("111".equals(password)){
throw new MyException("密码错误,请重新输入,谢谢!");
}
this.password = password;
}
}
class MyException extends Exception {
private String msg;
public String getPassword() {
return msg;
}
public void setPassword(String msg) {
this.msg = msg;
}
public MyException() {
super();
}
public MyException(String msg) {
super(msg);
this.msg = msg;
}
}