文章目录
类的成员
属性(Field)
-
语法格式:
修饰符 数据类型 属性名 = 初始化值;修饰符::private, 缺省, protected, public, (static,final暂不考虑)
数据类型:任何基本数据类型或任何引用数据类型
属性名:属于标识符,符合命名规则和规范即可。 -
成员变量(属性)和局部变量的区别:
/ 成员变量 局部变量 声明的位置 直接声明在类中 方法形参或内部、代码块内、构造器内等 修饰符 private, public, static, final 等 不能用权限修饰符,可以用final修饰 初始化值 有默认初始化值(0/0L/0.0/0.0F/’\u0000’/false/null) 没有默认化初始值,必须显示赋值,方可使用 内存加载位置 堆空间 或 静态域内 栈空间
方法(Method)
-
方法声明的格式:
修饰符 返回值类型 方法名 ( 参数类型 形参1, 参数类型 形参2, …){
方法体程序代码
return 返回值;
}修饰符:public, protected, 缺省, private等。
返回值类型:没有返回值使用void -
注 意:
方法被调用一次,就会执行一次
没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。
定义方法时,方法的结果应该返回给调用者,交由调用者处理。
方法中只能调用方法或属性, 不可以在方法内部定义方法。 -
方法的重载(overload)
- 重载的概念
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。 - 重载的特点:
与返回值类型无关,只看参数列表,且参数列表必须不同。 (参数个数或参数类型)。调用时, 根据方法参数列表的不同来区别。
- 重载的概念
-
可变个数的形参
- 声明格式: 方法名(参数的类型名 …参数名)
- 可变参数:方法参数部分指定类型的参数个数是可变多个: 0个, 1个或多个
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的
- 方法的参数部分有可变形参,需要放在形参声明的最后
- 在一个方法的形参位置,最多只能声明一个可变个数形参
-
方法参数的值传递机制
方法,必须由其所在类或对象调用才有意义。若方法含有参数:形参:方法声明时的参数
实参: 方法调用时实际传给形参的参数值Java里方法的参数传递方式只有一种: 值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
构造器(构造方法)
-
格式
修饰符 类名 (参数列表){ 初始化语句; }
-
根据参数不同,构造器可以分为如下两类:
隐式无参构造器(系统默认提供)
显式定义一个或多个构造器(无参、有参) -
注 意:
Java语言中,每个类都至少有一个构造器
默认构造器的修饰符与所属类的修饰符一致
一旦显式定义了构造器, 则系统不再提供默认构造器
一个类可以创建多个重载的构造器
父类的构造器不可被子类继承 -
构造器重载(参数列表必须不同)
public class Person{ public Person(String name, int age, Date d) {this(name,age);…} public Person(String name, int age) {…} public Person(String name, Date d) {…} public Person(){…} }
代码块
-
代码块(或初始化块)的作用:
对Java类或对象进行初始化
-
代码块(或初始化块)的分类:
一个类中代码块若有修饰符, 则只能被static修饰, 称为静态代码块(static block), 没有使用static修饰的, 为非静态代码块。static代码块通常用于初始化static的属性
-
静态代码块:用static 修饰的代码块
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
-
非静态代码块:没有static修饰的代码块
- 可以有输出语句。
- 可以对类的属性、 类的声明进行初始化操作。
- 除了调用非静态的结构外, 还可以调用静态的变量或方法。
- 若有多个非静态的代码块, 那么按照从上到下的顺序依次执行。
- 每次创建对象的时候, 都会执行一次。 且先于构造器执行。
-
程序中成员变量赋值的执行顺序
默认成员变量的默认初始化 --> 显式初始化、 多个初始化块依次被执行( 同级别下按先后顺序执行)–> 构造器再对成员进行初始化操作 --> 通过” 对象.属性” 或” 对象.方法” 的方式, 可多次给属性赋值
内部类(Inner class)
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
Inner class的名字不能与包含它的外部类类名相同;
-
分类:
成员内部类(static成员内部类和非static成员内部类)
局部内部类(不谈修饰符)、匿名内部类 -
成员内部类作为类的成员的角色:
和外部类不同, Inner class还可以声明为private或protected;
可以调用外部类的结构
Inner class 可以声明为static的, 但此时就不能再使用外层类的非static的成员变量; -
成员内部类作为类的角色:
可以在内部定义属性、 方法、 构造器等结构
可以声明为abstract类 , 因此可以被其它的内部类继承
可以声明为final的
编译以后生成OuterClass$InnerClass.class字节码文件( 也适用于局部内部类) -
注意:
- 非static的成员内部类中的成员不能声明为static的, 只有在外部类或static的成员内部类中才可声明static成员。
- 外部类访问成员内部类的成员, 需要“内部类.成员”或“内部类对象.成员”的方式
- 成员内部类可以直接使用外部类的所有成员, 包括私有的数据
- 当想要在外部类的静态成员部分使用内部类时, 可以考虑内部类声明为静态的
-
内部类的声明:
class 外部类{ 方法(){ class 局部内部类{ } } { class 局部内部类{ } } }
-
内部类的使用
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型 -
局部内部类的特点
内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
局部内部类可以使用外部类的成员,包括私有的。
局部内部类可以使用外部方法的局部变量,但是必须是final的。 由局部内部类和局部变量的声明周期不同所致。
局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
局部内部类不能使用static修饰,因此也不能包含静态成员 -
匿名内部类
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
格式:
new 父类构造器(实参列表)|实现接口(){ //匿名内部类的类体部分 }
特点:
匿名内部类必须继承父类或实现接口 匿名内部类只能有一个对象 匿名内部类对象只能使用多态形式引用
面向对象特征
封装与隐藏
-
我们程序设计追求“高内聚,低耦合”。
高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
低耦合 : 仅对外暴露少量的方法用于使用。 -
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说, 把该隐藏的隐藏起来,该暴露的暴露出来。 这就是封装性的设计思想。
-
Java中通过将数据声明为私有的(private), 再提供公共的( public)
方法:getXxx()和setXxx()实现对该属性的操作, 以实现下述目的:隐藏一个类中不需要对外提供的实现细节;
使用者只能通过事先定制好的方法来访问数据, 可以方便地加入控制逻辑,限制对属性的不合理操作;
便于修改, 增强代码的可维护性; -
四中访问权限修修饰符
修饰符 类内部 同一个包 不同包的子类 同一个工程 private Yes default(缺省) Yes Yes protected Yes Yes Yes public Yes Yes Yes Yes 对于class的修饰符只可以使用public或default(缺省)
public类可以在任何地方被访问
default类只可以被同一包内部的类访问
继承性(inheritance)
-
继承类语法规则:
class Subclass extends Superclass{ }
-
作用:
减少了代码的冗余,提高了代码的复用性
更有利于功能的扩展
让类与类之间产生了关系,提供了多态的前提提示:不要仅为了获取其他类中的某个功能而去继承(子类 is a 父类)
-
关于继承的规则:
1、子类继承了父类,就继承了父类的方法和属性。
2、 在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。
3、子类不能直接访问父类中私有的(private)的成员变量和方法。
4、Java只支持单继承和多层继承, 不允许多重继承:一个子类只能有一个父类,一个父类可以派生出多个子类 -
方法的重写:
定义:在子类中可以根据需要对从父类中继承来的方法进行改造, 也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
要求:
1、子类重写的方法必须和父类被重写的方法具有相同的方法名称、 参数列表
2、子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
3、子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限(子类不能重写父类中声明为private权限的方法)
4、子类方法抛出的异常不能大于父类被重写方法的异常注意:
子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写) 。因为static方法是属于类的,子类无法覆盖父类的方法。重写(override)与重载(overload)的区别:
1、 方法的重载和重写都是实现多态的方式。
重载实现的是编译时的多态性,而重写实现的是运行时的多态性。
重载发生在一个类中,方法名相同参数列表不同(参数类型不同、参数个数不同、顺序不同)则称之为发生了方法的重载,或两个方法互为重载。重写发生在继承过程中,子类继承父类公开的方法,不能满足子类的需求时,将父类的方法进行重写
2、方法重载的规则:
方法名一致,参数列表中参数的顺序,类型,个数不同。
重载与方法的返回值无关,存在于父类和子类,同类中。
3、 方法重写的规则:
返回值类型、方法名、参数列表不能修改
方法体根据需求重写 修饰符访问范围大于或等于父类
多态性
-
多态性,是面向对象中最重要的概念, 在Java中的体现:
对象的多态性:父类的引用指向子类的对象可以直接应用在抽象类和接口上
-
Java引用变量有两个类型: 编译时类型和运行时类型。 编译时类型由声明该变量时使用的类型决定, 运行时类型由实际赋给该变量的对象决定。 简称: 编译时, 看左边;运行时, 看右边。
-
对象的多态 —在Java中,子类的对象可以替代父类的对象使用
一个变量只能有一种确定的数据类型
一个引用类型变量可能指向(引用)多种不同类型的对象 -
子类可看做是特殊的父类, 所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
-
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
-
instanceof 操作符
x instanceof A:检验x是否为类A的对象,返回值为boolean型。要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B, x instanceof A值也为true。 -
对象类型转换 (Casting )
基本数据类型的Casting:1、 自动类型转换:小的数据类型可以自动转换成大的数据类型
2、 强制类型转换: 可以把大的数据类型强制转换(casting)成小的数据类型对Java对象的强制类型转换称为造型
1、从子类到父类的类型转换可以自动进行
2、从父类到子类的类型转换必须通过造型(强制类型转换)实现
3、无继承关系的引用类型间的转换是非法的
4、在造型前可以使用instanceof操作符测试一个对象的类型 -
虚拟方法调用(Virtual Method Invocation)-多态情况下:
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的,即动态绑定。
抽象(abstract)
-
抽象类与抽象方法概述
用abstract关键字来修饰一个类, 这个类叫做抽象类。
用abstract来修饰一个方法, 该方法叫做抽象方法。抽象方法只有方法的声明,没有方法的实现。以分号结束。
含有抽象方法的类必须被声明为抽象类。
抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
不能用abstract修饰变量、代码块、构造器;
不能用abstract修饰私有方法、静态方法、 final的方法、 final的类。 -
抽象类的应用
模板方法设计模式(TemplateMethod)
接口(interface)
-
概述
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守
接口(interface)是抽象方法和常量值定义的集合。 -
接口的特点
- 用interface来定义。
- 接口中的所有成员变量都默认是由public static final修饰的。
- 接口中的所有抽象方法都默认是由public abstract修饰的。
- 接口中没有构造器。
- 接口采用多继承机制。
-
定义Java类的语法格式: 先写extends,后写implements
一个类可以实现多个接口, 接口也可以继承其它接口。
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
接口的主要用途就是被实现类实现。 (面向接口编程)
与继承关系类似,接口与实现类之间存在多态性
接口和类是并列关系, 或者可以理解为一种特殊的类。 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前), 而没有变量和方法的实现。 -
接口的应用
代理模式(Proxy)
-
Java 8中关于接口的改进
java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
静态方法: 使用 static 关键字修饰。 可以通过接口直接调用静态方法 ,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
默认方法: 默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如: java 8 API中对Collection、 List、 Comparator等接口提供了丰富的默认方法。
若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现: 接口冲突。
解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守: 类优先原则。 接口中具有相同名称和参数的默认方法会被忽略。
关键字
this
- 在Java中, this关键字比较难理解,它的作用和其词义很接近。
它在方法内部使用,即这个方法所属对象的引用;
它在构造器内部使用,表示该构造器正在初始化的对象。
this 可以调用类的属性、方法和构造器
当在方法内需要用到调用该方法的对象时,就用this。 - 注意:
可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了
“this(形参列表)”
"this(形参列表)“必须声明在类的构造器的首行!
在类的一个构造器中,最多只能声明一个"this(形参列表)”
package
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在
的包。 (若缺省该语句,则指定为无名包)。它的格式为:
package 顶层包名.子包名 ;
包对应于文件系统的目录, package语句中,用 “.” 来指明包(目录)的层次;
包通常用小写单词标识。通常使用所在公司域名的倒置: com.atguigu.xxx
包的作用:
包帮助管理大型软件系统: 将功能相近的类划分到同一个包中。 比如: MVC的设计模式包可以包含类和子包, 划分项目层次, 便于管理 解决类命名冲突的问题控制访问权限
JDK中主要的包介绍
1、 java.lang----包含一些Java语言的核心类, 如String、 Math、 Integer、 System和Thread, 提供常用功能
2.、java.net----包含执行与网络相关的操作的类和接口。
3、 java.io ----包含能提供多种输入/输出功能的类。
4、 java.util----包含一些实用工具类, 如定义系统特性、 接口的集合框架类、 使用与日期日历相关的函数。
5、 java.text----包含了一些java格式化相关的类
6、 java.sql----包含了java进行JDBC数据库编程的相关类/接口
7、 java.awt----包含了构成抽象窗口工具集(abstract window toolkits) 的多个类, 这
些类被用来构建和管理应用程序的图形用户界面(GUI)。
import
为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类或全部类(.*)。 import语句告诉编译器到哪里去寻找类。
语法格式:import 包名. 类名;
注意:
1、 在源文件中使用import显式的导入指定包下的类或接口
2、声明在包的声明和类的声明之间。
3、 如果需要导入多个类或接口,那么就并列显式多个import语句即可
4、 举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。
5、 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
6、 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
7、 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
8、 import static组合的使用:调用指定类或接口下的静态的属性或方法
super
- 在Java类中使用super来调用父类中的指定操作:
super可用于访问父类中定义的属性
super可用于调用父类中定义的成员方法
super可用于在子类构造器中调用父类的构造器
- 注意:
尤其当子父类出现同名成员时, 可以用super表明调用的是父类中的成员
super的追溯不仅限于直接父类
super和this的用法相像, this代表本类对象的引用, super代表父类的内存空间的标识
子类中所有的构造器默认都会访问父类中空参数的构造器
当父类中没有空参数的构造器时, 子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。 同时, 只能”二选一”, 且必须放在构造器的首行
如果子类构造器中既未显式调用父类或本类的构造器, 且父类中又没有无参的构造器, 则编译出错
- this和super的区别
No. | 区别点 | this | super |
---|---|---|---|
1 | 访问属性 | 访问本类中的属性,如果本类没有此属性则从父类中继续查找 | 直接访问父类的属性 |
2 | 调用方法 | 访问本类中的方法,如果本类中没有此方法则从父类中继续查找 | 直接访问父类中的方法 |
3 | 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
static
-
使用范围:
在Java类中, 可用static修饰属性、 方法、 代码块、 内部类
类变量(class Variable)(类属性)由该类的所有实例共享
类方法(class method):没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法。在static方法内部只能访问类的static修饰的属性或方法, 不能访问类的非static的结构。 -
被修饰后的成员具备以下特点:
随着类的加载而加载
优先于对象存在
修饰的成员,被所有对象所共享
访问权限允许时,可不创建对象,直接被类调用 -
类属性、类方法的设计思想
类属性作为该类各个对象之间共享的变量。 在设计类时,分析哪些属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
final
在Java中声明类、 变量和方法时, 可使用关键字final来修饰,表示“最终的” 。
-
final标记的类不能被继承。 提高安全性, 提高程序的可读性。
String类、 System类、 StringBuffer类
-
f i n a l 标 记 的 方 法 不 能 被 子 类 重 写 \color{red}{final标记的方法不能被子类重写} final标记的方法不能被子类重写。
比如: Object类中的getClass()。
-
f i n a l 标 记 的 变 量 ( 成 员 变 量 或 局 部 变 量 ) 即 称 为 常 量 。 名 称 大 写 , 且 只 能 被 赋 值 一 次 \color{red}{final标记的变量(成员变量或局部变量)即称为常量。 名称大写, 且只能被赋值一次} final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次
final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋值, 然后才能使用。
补充
Object 类的使用
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类, 则默认父类为java.lang.Object类
- Object类中的主要结构
NO. | 方法名 | 类型 | 描述 |
---|---|---|---|
1 | public Object() | 构造 | 构造器 |
2 | public boolean equals(Object Obj) | 普通 | 对象比较 |
3 | public int hashCode() | 普通 | 取得Hash码 |
4 | public String toString() | 普通 | 对象打印时调用 |
… | … | … | … |
- toString() 方法
- toString()方法在Object类中定义, 其返回值是String类型, 返回类名和它的引用地址。
- 在进行String与其它类型数据的连接操作时, 自动调用toString()方法
- 可以根据需要在用户自定义类型中重写toString()方法(如String 类重写了toString()方法, 返回字符串的值。)
- 基本类型数据转换为String类型时, 调用了对应包装类的toString()方法
==
操作符与equals方法
-
== :
- 基本类型比较值:只要两个变量的值相等, 即为true。
- 引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,
==
才返回true。用
==
进行比较时, 符号两边的数据类型必须兼容(可自动转换的基本数据类型除外), 否则编译出错
-
equals()
- 所有类都继承了Object, 也就获得了equals()方法。 还可以重写。
只能比较引用类型, 其作用与
==
相同,比较是否指向同一个对象 - 当用equals()方法进行比较时, 对类File、 String、 Date及包装类(Wrapp。er Class) 来说, 是比较类型及内容而不考虑引用的是否是同一个对象
原因:在这些类中重写了Object类的equals()方法。
- 当自定义使用equals()时, 可以重写。 用于比较两个对象的“内容” 是否都相等
- 重写equals()方法的原则:
对称性: 如果x.equals(y)返回是“ true” , 那么y.equals(x)也应该返回是“true” 。
自反性: x.equals(x)必须返回是“true” 。
传递性: 如果x.equals(y)返回是“true” , 而且y.equals(z)返回是“true” ,那么z.equals(x)也应该返回是“true” 。
一致性: 如果x.equals(y)返回是“true” , 只要x和y内容一直不变, 不管你重复x.equals(y)多少次, 返回都是“true” 。
任何情况下, x.equals(null), 永远返回是“false” ;x.equals(和x不同类型的对象)永远返回是“false” 。
- 所有类都继承了Object, 也就获得了equals()方法。 还可以重写。
-
==
和equals的区别==
既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址- equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是
==
;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。 - 具体要看自定义类里有没有重写Object的equals方法来判断。
- 通常情况下,重写equals方法,会比较类中的相应属性是否都相等。
包装类(Wrapper)的使用
-
针对八种基本数据类型定义相应的引用类型—包装类(封装类),有了类的特点,就可以调用类中的方法, Java才是真正的面向对象
基本数据类型 包装类 byte Byte short Short int Integer long Long float Float double Double boolean Boolean char Charater -
基本类型、包装类与String类间的转换
设计模式
单例 (Singleton)设计模式
-
设计模式
在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。 设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。 ”套路”
-
单例设计模式
采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
-
饿汉式
class Singleton{ //私有化构造器 private Singleton() { } //实例化该类 private static Singleton1 single = new Singleton(); //提供公共的静态方法,返回当前类的实例 public static Singleton getInstance() { return single; } }
-
懒汉式
//暂时存在线程安全问题 class Singleton { //私有化构造器 private Singleton() { } //内部提供一个当前类的实例 private static Singleton single; //提供公共的静态方法,返回当前类的实例 public static Singleton getInstance() { if(single == null) { single = new Singleton(); } return single; } }
-
单例模式的优点:
由于单例模式只生成一个实例, 减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
栗子:java.lang.Runtime -
单例(Singleton)设计模式-应用场景
网站的计数器,一般也是单例模式实现,否则难以同步.
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作, 否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
项目中, 读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
Application 也是单例的典型应用
Windows的Task Manager (任务管理器)就是很典型的单例模式
Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
- 解决的问题:
- 当功能内部一部分实现是确定的, 一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
- 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
- 模板方法设计模式是编程中经常用得到的模式。 各个框架、 类库中都有他的影子, 比如常见的有:
数据库访问的封装
Junit单元测试
JavaWeb的Servlet中关于doGet/doPost方法调用
Hibernate中模板程序
Spring中JDBCTemlate、 HibernateTemplate等
代理模式(Proxy)
-
概述:
代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
-
应用场景:
安全代理: 屏蔽对真实角色的直接访问。
远程代理: 通过代理类处理远程方法调用(RMI)
延迟加载: 先加载轻量级的代理对象, 真正需要再加载真实对象 -
分类
静态代理(静态定义代理类)
动态代理(动态生成代理类): JDK自带的动态代理, 需要反射等知识
----------------------------------------------华丽分割线---------------------------------------------------------
系统复习java第一弹,本文资源来源于尚硅谷公开课程:尚硅谷_Java零基础教程-java入门必备-初学者从入门到精通全套完整版(宋红康主讲)