Lesson10_封装(encapsulation)
回顾
String的创建和常用方法
String s1 = “abcd”;
String s2 = new String(“abcd”); // 堆、方法区各有一个对象
s1.length()
s1.contains(xxx)
s1.equals(xxx)
s1.compareTo(xxx)
s1.indexOf(xxx)
s1.lastIndexOf(xxx)
s1.split(xxx)
s1.trim()
s1.startsWith(xxx)
s1.endsWith(xxx)
s1.replace(xx,xx)
s1.toLowerCase()
s1.toUpperCase()
面向对象的优点:可复用、信息隐藏
Java内存:栈、堆、方法区、垃圾回收器
类的定义:类名、属性、方法
创建对象 new
成员访问符 .
变量的作用域
封装
-
概念:是面向对象(OOP)三大特征之一;是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。将东西包装在一起,然后以新的完整形式呈现出来。在一个类中就是讲方法和字段包装到一个单元中,单元以类的形式实现。将信息隐藏,对象的实现细节隐藏,不让外部直接访问。简单的说,将数据和方法包装进类中,隐藏具体的实现,共同被称之为封装,其结果是一个同时带有特征和行为的数据类型。
比如定义类,定义其属性、方法的过程称之为封装类。
抽象、打包
抽象:去掉不重要、不关注的细节
打包:把关注的信息保留
将属性、方法封装在一个类中,隐藏具体的实现细节,称之为封装。
- 信息隐藏的原因包括:
- 对模块任何实现细节所作的更改不会影响使用该模块的代码。
- 防止用户意外修改数据。
- 使模块易于使用和维护。
-
四种访问修饰权限:public > protected > 不加 > private (访问修饰符:只有三个)
public : 公开,所有人都可以直接访问。整个工程中,只要拿到你的对象,就可以访问该对象的所有公开成员
protected : 受保护的,同一个包中的类或者跨包的子类可以访问
不加 :包访问权限,同一个包中的类都可以访问
private : 私有,只有该类的内部可以访问。出了这个类,没有人可以访问其中的私有信息
-
属性封装的原则:
- 能私有一律私有,除非必须公开
- 修改属性的可见性来限制对属性的访问
- 为每个属性创建一对赋值(setter)方法和取值(getter)方法,用于公开对这些属性的访问接口。
- 在setter和getter方法中,根据需要加入对属性操作的限制。
-
方法封装的原则:
- 按需决定是否公开。如果希望别人直接访问,则公开;否则,私有。私有方法也叫帮助方法
- 隐藏方法的是实现细节(方法体),向外部提供公开的接口(方法名),以供安全使用
- 简化调用,方便修改维护
-
好处:
- 通过方法来控制成员变量的操作,提高了代码的安全性。
- 把代码用方法进行封装,提高了代码的复用性。
UML类图(要求:能看懂)
- 概念:unified Modeling Language(UML)又称统一建模语言或标准建模语言,它是一个支持模型化和软件系统开发的图形化语言。为软件开发的所有阶段提供模型化和可视化支持,包括由需求分析到规格,到构造和配置。
-
三段:类名(Person)、属性(-age:int)、方法(+sayHi()void)
-
访问权限
- + public
- - private
- # protected
-
类和类之间的关系
http://www.cnblogs.com/liuling/archive/2013/05/03/classrelation.html
构造方法
-
作用:
- 构造器也叫构造方法(constructor),用于对象的初始化。给新创建出来的对象的属性赋值(一行语句就可以给新对象的多个属性赋值)
- 构造方法负责对象初始化工作,为对象的属性赋合适的初始值。创建对象时,其类的构造方法确保在用户操作对象之前,系统保证初始化的进行。(即对属性进行初始化)
-
构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
-
语法规则
- 构造方法名与类名相同
- 没有返回类型
- 方法实现主要为字段赋初始值
- 不能被static、final、synchronized、abstract和native修饰
-
声明格式
[修饰符] 类名(形参列表){ //n条语句 }
-
注意:
- 通过new关键字调用!!
- 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
- 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加!
- 构造器的方法名必须和类名一致!
-
与方法有什么不同:
- 方法名必须和类名完全相同
- 没有返回类型
- new调用,创建对象
-
当我们在构造一个对象的时候,一定会调用构造方法,所以Java系统保证每个类至少有一个构造方法
- 如果你没写构造方法,系统自动提供一个无参构造方法(隐式提供,看不见,但是能用)
- 如果你写了任何一个构造方法,系统都不再提供构造方法。(如果写了一个有参的,则没有无参的了)
- 注意:如果写了有参构造方法了,建议再写上无参构造方法,为后期的继承做铺垫:子类所有的构造方法,第一条语句都会自动调用父类的无参构造方法。如果父类没有无参构造方法,子类所有的构造方法都会报错。
-
调用构造方法不会创建对象。new + 构造方法,才会创建对象。究其本质,是new在创建对象。
-
构造方法的重载
封装中的关键字
this
-
当在方法中出现了局部变量和成员变量同名的时候,那么在方法中怎么区别局部变量成员变量?可以在成员变量名前面加上this.来区别成员变量和局部变量
-
对象创建的过程:构造方法是创建Java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。创建一个对象分为如下四步:
- 分配对象空间,并将对象成员变量初始化为0或空
- 执行属性值的显示初始化
- 执行构造方法
- 返回对象的地址给相关的变量
- this含义:当前对象的引用,本质是一个引用变量,解决参数与属性重名的问题。由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表当前对象。
- 用法:
- this 调用方法的那个对象的引用。
- this. 当成员变量和局部变量重名时,用作成员变量的前缀
- this() / this(xxx) 调用该类对应参数的构造方法,只能用在构造方法中的第一条语句
- this不能用于static方法中。
- this只能用在构造方法(构造方法)或者方法中,用于获得调用当前的构造方法的对象引用。可以和任何的对象引用一样来处理这个this对象。
- 总结:
- 在类的方法中使用this关键字代表的是调用此方法的对象的引用(可以认为this和引用变量是同一个人,存的是同样的地址)
- this可以看做是一个变量,它的值是当前对象的引用
- 使用this关键字可以处理方法中的成员变量和形参同名的问题
- 当在方法内需要用到调用该方法的对象时,就可以用this
- 在类的构造方法中可以调用this([参数列表])来调用该类的指定构造方法
- this关键字还有一个重大的作用就是返回类的引用。如在代码中,可以使用return this来返回某个类的引用。此时,这个this关键字就代表类的名称。
- 说明:
- 当实例变量和局部变量重名,Java平台会按照先局部变量、后实例变量的顺序寻找。即,方法中使用到的变量的寻找规律是先找局部变量,再找实例变量。如果没用找到,将会有一个编译错误而无法通过编译。
- 如果使用this.a,则不会在方法(局部变量)中寻找变量a,而是直接去实例变量中去寻找,如果寻找不到,则会有一个编译错误。
- 在一个方法内,如果没有出现局部变量和实例变量重名的情况下,是否使用this关键字是没有区别的。
- 在同一个类中,Java普通方法的互相调用可以省略this+点号,而直接使用方法名+参数。因为Java编译方法会帮我们加上。
static
-
当在定义类的时候,类中都会有相应的属性和方法。而属性和方法都是通过创建本类对象调用的。当在调用对象的某个方法时,这个方法没有访问到对象的特有数据时,方法创建这个对象有些多余。可是不创建对象,方法又调用不了,这时就会想,那么我们能不能不创建对象,就可以调用方法呢?
可以的,我们可以通过static关键字来实现。static是静态修饰符,一般修饰成员。被static修饰的成员属于类,不属于单个这个类的某个对象。
被static修饰的成员可以并且建议通过类名直接访问。也可以通过某个对象访问到属于类的静态成员,多个对象共享使用同一个静态成员。
-
含义:在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效,多个对象共享,可以通过类名直接调用
-
特点:
- static是静态修饰符,一般修饰成员。
- 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
- 一般用“类名.类属性/方法”来调用。(也可以通过对象引用或类名(不需要实例化)访问静态成员。)
- 被static修饰的成员又叫类成员,不叫对象成员。
- 被static修饰的成员属于类,但是会影响每一个对象。
- 在static方法中不可直接访问非static的成员。
-
注意:static修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象的。
-
先后顺序 : 静态成员和类一起加载,先于对象存在。
- 静态方法不能访问非静态的成员,不能出现this关键字,只能访问外部静态的属性或者方法。
-
对象共享 :一个类,可以创建多个对象。所有对象共享同一份数据,一改全改。
-
注意:
- 静态方法中只能访问外部的静态成员,静态方法中不能出现this关键字。
- 非静态的方法可以访问静态的内容和非静态的内容。
- 此外给属性和方法都加上static并不好,因为它破坏了面向对象的特点。我们说每一个对象都有自己的属性,若其都加上static,就变成了大家都可以共享了,破坏了面向对象的封装性。此外如果属性被static修饰的话,说明属性的生命周期比较长,只有当程序结束的时候,内存才会被释放,而如果是某个对象的属性,当该属性运行完就会被释放,占用内存的时间比较短。那什么时候才用static呢?
- 类中没有属性或者属性都是静态的,可以把方法声明为static。
- 类中没有任何属性,只有方法,而且这些方法专门为其他的类服务,比如Arrays类。它里面是没有属性的,它是专门提供很多方法来对数组进行操作,这种情况就可以把类中的所有方法定义为静态的,调用起来就很方便,不用产生对象,直接通过类名.方法名直接访问。
静态代码块、普通代码块、构造方法
分别执行几次,先后顺序是什么
- 静态代码块 类加载的时候,执行一次,在普通代码块和构造方法之前
- 普通代码块 每创建一个对象,都会执行一次,在静态代码块之后,构造方法之前
- 构造方法 调用哪个执行哪个,不调用不执行
单例模式
-
设计模式
-
设计模式的概念:设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。
-
设计模式主要是基于以下的面向对象设计原则:
- 对接口编程而不是对实现编程。
- 优先使用对象组合而不是继承。
-
六大设计原则
- 单一职责原则
- 接口隔离原则
- 迪米特法则
- 依赖倒置原则
- 开闭原则
- 里氏替换原则
-
-
含义:例,实例,对象。单例,有且只有一个对象。单列模式的意思就是只有一个实列,单列模式确保某一个类只有一个实列,而且自行实例化并向整个系统提供这个实列,这个类称之为单列类。
-
特点:
- 只有一个实例;
- 自我实例化;
- 自行向整个系统提供这个实列(提供全局访问点)。
- 因此当系统中只需要一个实例对象或者系统中只允许一个公共访问点,除了这个公共访问点外,不能通过其他访问点访问该实例时,可以使用单例模式。
-
优点:
- 单例模式的主要优点就是节约系统资源、提高了系统效率
- 也能够严格控制客户对它的访问
- 就导致了单例类的职责过重,违背了“单一职责原则”
- 同时也没有抽象类,所以扩展起来有一定的困难
-
应用实例
- 一个班级只有一个班主任
- Windows是多线程多进程的,在操作一个文件的时候,就不可避免的出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例进行。
- 一些设备管理器常常设计为单例模式,比如一个电脑有两个喇叭,在输出的时候就要处理不能两个喇叭播放同一个文件。
-
饿汉式(立即加载方式)
类加载时就创建对象供外部使用,除非系统重启,这个对象不会改变,所以本身线程是安全的。但是会较早的占据内存空间。浪费一点内存,访问时速度快。牺牲空间,换取时间。
public class SingleTon { private static SingleTon singleTon = new SingleTon();// 自己创建 private SingleTon(){ System.out.println("私有化构造方法,别人就new不了自己了"); } // 私有化属性后,提供的公开访问方法 public static SingleTon getInstance(){ return singleTon; } }
-
懒汉式
不着急,什么时候用,什么时候创建,懒汉式也体现了缓存的思想,延时加载就是一开始不要加载资源或者数据,一直到马上就要使用这个资源或数据了,才去加载。首次使用对象时,会浪费时间。牺牲时间,换取空间。
public class SingleTon2 { private static SingleTon2 singleTon = null;// 不着急,等用的时候再创建 private SingleTon2(){ System.out.println("私有化构造方法,别人就new不了自己了"); } // 私有化属性后,提供的公开访问方法 public static SingleTon2 getInstance(){ if(singleTon == null){ // 首次使用的时候突然发现还没有创建对象 singleTon = new SingleTon2(); // 等待对象的创建 } return singleTon;// 后续使用时不再创建,直接返回即可 } }
方法重载
-
概念:同一个类中,同名不同参的多个方法,互为重载方法。这种现象是方法重载
System.out.println(); System.out.println(1); System.out.println(2.5); System.out.println(false); System.out.println("abc"); // 同一个类的多个构造方法,也叫方法重载 public Person(){} public Person(String name, int age){ this.name = name; this.age = age; }
package
-
打包 :资源分类管理,避免类名冲突
-
含义:
- 标准Java库是由一系列包组成,标准Java包就是层次型包结构,就如同我们电脑上的D盘的子目录一样,我们可以使用嵌套层次结构来组织包。
- Java的包是为了规划代码,防止命名冲突和混乱。所以Java出现了打包机制。
- 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
- 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
-
包声明
- 创建包的时候,你需要为这个包取一个合适的名字。之后,如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。
- 包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。 - 打包语句必须作为.java文件的第一条语句。
-
规范的包名:全小写,域名倒置 (域名 www.baidu.com ==> com.baidu.xxx业务)
-
通常是类的第一句非注释性语句。
-
程序中的包的概念,在操作系统中就是文件夹
-
java中的常用包
- java.lang:包含一些java预言的核心类,如String、Math、Integer、System和Thread,提供常用功能
- java.awt:包含了构成抽象窗口工具集的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
- java.net:包含执行与网络相关的操作类。
- java.io:包含能提供多种输入/输出功能的类。
- java.util:包含一些工具类,如定义系统特性、使用与日期日历相关的函数。
-
如果我们要使用其他包的类,需要使用import导入,从而可以在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。import后,便于编写代码,提高可维护性。
-
注意:
- Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。
- 如果导入两个同名的类,只能用包名+类名来显示调用相关类
- import java.util.*;//导入该包下所有的类。会降低编译速度,但不会降低运行速度。
-
静态导入:静态导入(static import)是在JDK1.5新增加的功能,其作用是用于导入指定类的静态属性,这样我们可以直接使用静态属性。
package cn.sxt; //以下两种静态导入的方式二选一即可 import static java.lang.Math.*;//导入Math类的所有静态属性 import static java.lang.Math.PI;//导入Math类的PI属性 public class Test2{ public static void main(String [] args){ System.out.println(PI); System.out.println(random()); } }
-
总结
- this的本质就是“创建好的对象的地址”! this不能用于static方法中。
- 在类中,用static声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效。在static方法中不可直接访问非static的成员。
- Java方法中所有参数都是“值传递”,也就是“传递的是值的副本”。也就是说,我们得到的是“原参数的复印件,而不是原件”。因此,复印件改变不会影响原件。
- 通过package实现对类的管理;如果我们要使用其他包的类,需要使用import导入,从而可以在本类中直接通过类名来调用。