内部类和设计模式
回顾
1 抽象类:
实例化对象没有意思,所以使用抽象类,
抽象类不能实例化
2 abstract关键字
abstract 修饰类表示抽象类
abstract 修饰方法 抽象方法
4 抽象方法
抽象方法没有方法体
抽象方法被子类重写
包含抽象方法的类一定是抽象类
5 抽象类
抽象类不能实例化对象
抽象类可以包含抽象方法,也可以包含非抽象方法
抽象类的抽象方法必须被子类重写,除非子类也是抽象类
6 static final abstract
final 和 abstract 不能一起使用
static和abstract不能一起使用
7接口 :语法:就是特殊的抽象类
功能:表示一个约定或能力
接口好处:
- 扩展类的功能,保持对外接口一致
- 接口实现了多重继承,完成类和任何实现接口子类的通信和交互
- 降低代码之间的耦合性
定义接口
public interface 接口名{
静态常量
抽象方法
}
jdk1.8 静态方法和默认方法
实现接口
class 类名 implements 接口名{
重写接口中抽象方法
}
一个类可以实现多个接口,只能继承一个类
接口与接口的关系: extends ,多继承
public interface Inter1{
}
public interface Inter2{
}
public interface Inter3 extends Inter1,Inter2{
}
今天任务
1.内部类
1.1 成员内部类
1.2 局部内部类
1.3 静态内部类
1.4 匿名内部类
2.设计模式
2.1 单例设计模式
2.2 简单工厂设计模式
教学目标
1.了解成员内部类、局部内部类和静态内部类的语法结构
2.了解各种内部类的注意事项
3.掌握匿名内部类的使用
4.掌握单例设计模式的实现
5.掌握简单工厂设计模式的实现
第一节 内部类
内部类:一个类中嵌套(包含)另外一个类。包含的类叫内部类,外层类叫外部类。
成员内部类:
局部内部类:
静态内部类:
匿名内部类:
#####1.1 成员内部类
作为外部类的成员存在,与成员变量和成员方法平级关系。
1.1.1 声明:
public class Out{
//成员变量
//成员方法
//成员内部类
访问权限 class In{
//成员变量
//成员方法
}
}
1.1.2 语法说明:
成员内部类的访问权限:任意的
1.1.3 如何创建成员内部类的对象:
由于成员内部类作为外部类的成员存在,若想访问类成员需要通过对象,所以成员内部类对象需要通过外部类 对象创建
语法:
//创建外部类对象
Out o = new Out();
//通过外部类找到内部类,通过外部类对象创建内部类对象
Out.In i = o.new In();
一步完成:
Out.In i2=new Out().new In();
1.1.4 如何在成员内部类中访问外部类的成员:
1.当外部类的属性和内部类属性不同名时,可以直接访问
2.当外部类属性与内部类属性同名时,格式:
外部类名.this.属性名
通过以上格式在内部类中访问外部类的同名属性
3.成员内部类中不能包含静态成员
1.1.5 成员内部类的字节码文件格式:
外部类名$内部类名.class
代码实现:
public class Out {
//成员变量
int a = 2;
//成员方法
public void fun() {
System.out.println(a);
}
//成员内部类
public class In{
//成员内部类的成员变量
int a = 3;
//成员内部类的成员方法
public void fun() {
Out.this.fun();
System.out.println(a);
System.out.println(Out.this.a);
}
}
}
import memberInnerClass.Out.In;
public class Test {
public static void main(String[] args) {
//先创建外部类对象
Out o = new Out();
//System.out.println(o.a);
//o.fun();
//创建成员内部类的对象
//通过外类的对象创建成员内部类对象
In i = o.new In();
//System.out.println(i.b);
i.fun();
}
}
#####1.2 局部内部类
作为局部成员存在,和局部变量平级。
1.2.1 声明:
public class Outer{
//成员变量
//成员方法
//局部内部类所在的方法
public void fun(){
//功能代码
//局部内部类
访问权限 class Inner{
//局部内部类的成员变量
//局部内部类的成员方法
}
}
}
1.2.2 说明:
局部内部类的访问权限:只能是默认
1.2.3 如何创建局部内部类对象:
直接在局部内部类所在的方法中创建对象并调用方法
1.2.4 如何在局部内部类中访问外部类的属性:
1.不同名,直接访问
2.同名,外部类名.this.属性名
3 局部内部类中不能包含静态成员。
4 局部内部类中访问局部变量,局部变量必须是final 常量 ,从jdk1.8之后final可以省略
1.2.5 字节码文件:
外部类名$编号内部类名.class
代码实现:
public class Outer {
//成员变量
int a = 3;
//成员方法
public void fun() {
class Inner{}
System.out.println("外部类的fun");
}
//局部内部类所在的方法
public void fun3() {
class In{}
//局部内部类
class Inner{
//成员变量
int a = 10;
//成员方法
public void fun() {
Outer.this.fun();
System.out.println(a);
System.out.println(Outer.this.a);
System.out.println("局部内部类的fun方法");
}
}
Inner i = new Inner();
i.fun();
}
}
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
//局部内部类具有作用域,所以调用外部类对象的fun3方法时会声明局部内部类并创建对象调用方法
o.fun3();
}
}
#####1.3 静态内部类(重点)
static关键字用法:修饰成员变量,成员方法,代码块
static关键字的第四个用法,修饰内部类(有要求的)
static修饰的内部类是静态内部类
static只能修饰类成员
使用static修饰的成员内部类是静态内部类
1.3.1 声明:
public class Out{
访问权限 static class In{
}
}
1.3.2 说明:
访问权限:任意的,一般使用public
使用static修饰的内部类,自动提升为普通类,相当于一个独立的类,和外部类级别相同
1.3.3 创建对象:
不需要外部类的对象,可以直接创建静态内部类的对象
格式:外部类.内部类 标识符 = new 外部类.内部类构造方法
1.3.4 访问外部类的成员:
1 静态内部类能直接访问外部类的静态成员
2 非静态的成员只能通过创建外部类对象访问
3 静态内部类中可以包含静态成员
1.3.5 字节码文件格式:
外部类名$内部类名.class(与成员内部类一样)
代码实现:
public class OuterClass {
static String s = "hello";
int a = 10;
public void fun() {
System.out.println("外部类的fun");
}
//静态内部类
public static class InnerClass{
int b = 20;
public void fun() {
System.out.println(s);
System.out.println();
System.out.println("内部类的fun");
}
}
}
import staticInnerClass.OuterClass.InnerClass;
public class Test {
public static void main(String[] args) {
//可以不创建外部类对象,直接创建静态内部类对象
InnerClass i = new InnerClass();
i.fun();
}
}
#####1.4 匿名内部类
1.4.1 什么是匿名内部类:
没有名字的内部类
1.4.2 原理产生原因:
由于接口和抽象类不能创建对象,若一个接口的实现类只需要使用一次,或一个抽象类的子类只需要使用一次,可以使用匿名内部类,匿名内部类只能创建一个对象
代码实现:
public interface I {
public abstract void fun();
}
public class Test{
public static void main(Strng[]args){
I i = new I(){
public void fun(){
//功能代码
}
};
i.fun1();//使用匿名内部类的对象(接口引用)调用匿名内部类中重写的接口中的方法
}
}
1.4.3 匿名内部类的注意事项:
1 匿名内部类中必须把抽象方法全部实现
2 匿名内部类中可以声明独有的属性和方法,但是由于接口引用不能访问实现类中独有的属性和方法,所以一般不在匿名内部类中声明独有的属性和方法
3 匿名对象:若在匿名内部类中声明了独有的方法或属性,可以使用匿名对象访问,不能通过对象名.方法名()访问。
1.4.4 lambda 表达式
入门使用
USB leishe= ()->System.out.println("镭蛇和电脑连接成功,开始工作");
代码实现:
public static void main(String[]args){
//匿名对象调用成员方法
new I(){
public void fun(){}
public void fun1(){
System.out.println("匿名内部类的fun1");
}
}.fun1();//使用匿名内部类的匿名对象调用匿名内部类中独有的方法
//new Animal().eat();
}
1.4.4 匿名内部类的字节码文件格式:
测试类$编号.class
匿名内部类只能使用一次,即便两次声明的匿名内部类完全一致,也是两个匿名内部类
####第二节 设计模式
设计模式
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
简单理解:特定问题的特定解决方法。
#####2.1 单例设计模式
2.1.1 什么是单例:
在程序运行,一个类只需要一个实例,不能出现多个实例,就叫单例。
2.1.2 单例的模式动机:
在一个系统或平台中,某个类的实例(对象),只需要有一个
一个朝代只能有一个皇帝,一个公司只能有一个老板
2.1.3 实现原理:封装
得到一个类的对象,需要通过new关键字,调用构造方法创建对象
实现过程:
分析:某个类只能有一个对象,但是构造方法只要一调用就会产生新的对象,可以通过封装将构造方法进行私有化;
若构造方法私有化,那么此类将没有对象
私有化的构造方法可以在类内部调用创建对象
2.1.4 需要完成的事项:
1)私有化构造方法;
2)在类内创建对象;
3)提供一个共有的方法,用来获取本类对象
2.1.5 实现方式:
单例分为懒汉式和饿汉式
核心:
构造方法私有:不能在类外随意创建对象
在类内部声明一个本类静态的对象作为属性
提供一个共有静态的方法用来获取本类对象
饿汉式代码实现:
public class Boss{
//属性
private String name;
private int age;
//私有化构造方法
private Boss(String name, int age){
this.name = name;
this.age = age;
}
//私有静态本类对象作为属性
private static Boss boss = new Boss("马云",12);
//提供共有静态方法获取本类对象
public static Boss getBoss(){
return boss;
}
}
懒汉式代码实现:
pulbic class King{
//属性
private String name;
private int age;
//私有构造方法
private King(String name, int age){
this.name = name;
this.age = age;
}
//私有静态本类对象
private static King king;
//共有静态方法获取本类对象
public static King getKing(){
if(king==null){
king = new King("唐太宗",12);
}
return king;
}
}
思考:懒汉式和饿汉式有什么区别?
书写上的区别:懒汉是调用方法是初始化对象,饿汉是声明同时初始化
使用上没有区别
存储时:在第一次获取单例类对象前,懒汉比饿汉节省空间
多线程操作时区别:懒汉式存在线程安全问题,饿汉式不存在
2.2 简单工厂设计模式
1.原理:多态
生活中的工厂:手机厂,电视厂,服装厂…
2.动机:
考虑一个简单的软件应用场景,一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等),这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。
3.优缺点:
优点:工厂类包含产品的判断逻辑,可以决定创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
缺点:由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
4.案例:
服装厂:生产服装分析:
需要一个服装厂类:工厂,类中具有生产服装的功能(创建服装对象)
服装类(父类产品):抽象类表示
服装子类(具体产品): 普通类表示
客户程序:使用工厂的程序。
/**
* 服装类
* @author wgy
*
*/
public abstract class Clothing {
//准备布料
public abstract void prepare();
//制作
public abstract void make();
//包装
public abstract void box();
}
public interface FuZhuang {
//成员方法:
public abstract void fun();
}
/**
* 裤子
* @author wgy
*
*/
public class Trousers extends Clothing{
@Override
public void prepare() {
System.out.println("准备制作裤子的布料......");
}
@Override
public void make() {
System.out.println("开始制作......");
}
@Override
public void box() {
prepare();
make();
System.out.println("包装完毕.....");
}
}
/**
* T恤
* @author wgy
*
*/
public class Tshirt extends Clothing{
@Override
public void prepare() {
System.out.println("准备制作T恤的布料...");
}
@Override
public void make() {
System.out.println("开始制作T恤......");
}
@Override
public void box() {
prepare();
make();
System.out.println("打包T恤.....");
}
}
public class Factory {
/**
* 创建对象方法
* 1 表示 Trousers
* 2 表示 Tshirt
* @return
*/
public static Clothing create(int type) {
Clothing clothing=null;
if(type==1) {
clothing=new Trousers();
}else if(type==2){
clothing=new Tshirt();
}
if(clothing!=null) {
clothing.box();
}
return clothing;
}
}
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("--------欢迎来到郑帅服装厂--------");
System.out.println("-----------1 裤子 2 T恤-----------------");
System.out.println("请选择购买的衣服");
Scanner input=new Scanner(System.in);
int choice=input.nextInt();
Clothing clothing=Factory.create(choice);
if(clothing!=null) {
System.out.println("购买成功");
}else{
System.out.println("购买失败");
}
}
}
总结
1 内部类
1.1 成员内部类
成员内部类和非静态属性、方法 级别相同
注意:
成员内部类可以直接访问外部类的非静态的属性和方法
成员内部类可以访问外部类的静态属性和方法
成员内部类中属性及方法和外部类的属性及方法相同时使用 外部类名.this.属性|方法
成员内部类中不能包含静态属性和方法
1.2 局部内部类
局部内部类,是包含在方法中,使用范围只限制在方法内。
注意:
局部内部类可以直接访问外部类的非静态的属性和方法
局部内部类可以访问外部类的静态属性和方法
如果局部内部类中属性及方法和外部类的属性及方法相同 外部类名.this.属性|方法
局部内部类不能包含静态属性和方法
局部内部类使用局部变量,局部变量必须是常量 final修饰
1.3 静态内部类
静态内部类:相当于一个外部类
只有内部类才可以是静态的
注意:
静态内部类可以直接访问外部类的静态属性和方法
静态内部类不能直接访问外部类的非静态属性和方法,需要创建对象访问
静态内部类中可以包含静态成员
1.4 匿名内部类
匿名内部类就是内部类的简写,主要用在接口中创建对象
Usb mouse=new Usb(){
public void service(){
}
};
mouse.service();
2 设计模式:特定问题的特定解决方法
2.1 单例设计模式 :
懒汉式
饿汉式
1 私有化构造方法
2 在类内部创建一个静态对象
3 通过一个公开的方法返回这个对象
2.2 简单工厂设计模式: 把对象的创建交给一个独立的工厂类创建。把对象的创建和使用分隔开
1 父类产品
2 子类产品
3 工厂
4 客户程序
默写
设计一个抽象商品类,具有名称和产地属性
非抽象食品类,继承商品类
非抽象日用品类,继承商品类
设计一个工具类,判断一件商品是食品还是日用品,若是食品输出“可以食用”,若是日用品输出“不可以食用”
作业
1.使用懒汉式实现单例设计模式
2.编写面包类,包含三个方法
prepare()准备
bake()烘烤
box打包
三个子产品:鸡蛋面包,奶油面包,鸡腿面包
面包工厂类:负责生产各种面包
使用简单工厂实现。
作业答案关注 +私信哦
面试题
//要求:使用已知的变量,在控制台输出30,20,10。
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}