一、访问控制权限
访问控制权限也就是针对于封装做了一个总结,本次来观察四种访问控制权限。
在之前只是简单的见到了封装性,但是对于封装是与访问控制权限有直接联系的。
在Java里面一共支持四种访问控制权限:public、protected、default、private,这四种访问控制权限特点如下所示:
No | 范围 | private | default | protected | public |
1 | 在同一个类中 | √ | √ | √ | √ |
2 | 在同一包的不同类 |
| √ | √ | √ |
3 | 在不同包的子类 |
|
| √ | √ |
4 | 在不同包的非子类 |
|
|
| √ |
除了public之外,对于封装可以使用private、protected、default,只不过一般不会去考虑使用default。
对于其它的权限基本上已经见过了,重点放在protected,这种权限它直接与包的定义有关。
范例:定义cn.zhai.demoa.A类
package cn.zhai.demoa; public class A { protected String info = "Hello"; }
范例:定义cn.zhai.demob.B类,此类继承A类
package cn.zhai.demob; import cn.zhai.demoa.A; public class B extends A {// 是A不同包的子类 public void print() { System.out.println("A类的info = " + super.info); } }
范例:测试
package test; import cn.zhai.demob.B; public class Test { public static void main(String[] args) { new B().print(); } }
B中的print()方法会输出A类中的info属性。
如果说现在是由Test类直接去输出A类中的info属性。
范例:错误的访问
package test; import cn.zhai.demoa.A; public class Test { public static void main(String[] args) { A a = new A(); System.out.println(a.info); } }
由于Test与A类不在同一个包,并且没有继承关系,所以是无法访问protected属性的。
总结:
- Java的封装性是以private、protected、default三种权限的定义;
- 对于权限的选择,给出以下建议:
· 声明属性就使用private;
· 声明方法就使用public;
- 关于命名要求:
· 类名称每一个单词的首字母大写,其余字母小写,例如:StudentInfo;
· 属性名称第一个单词字母小写,而后每个单词字母首字母大写,例如:studentName;
· 方法名称第一个单词字母小写,而后每个单词字母首字母大写,例如:getName();
· 常量名称使用大写字母表示,例如:MSG;
· 包名称使用小写字母,例如:cn.zhai.demo;
二、构造方法私有化
1、单例设计模式(Singleton)
在正常情况下,如果给了你一个类,那么只有通过产生对象之后才可以操作这个类。
范例:观察如下代码
class Singleton { public void print() { System.out.println("Hello World!!!"); } } public class Demo { public static void main(String args[]) { Singleton s = null;// 声明对象 s = new Singleton();// 实例化对象 s.print(); } }
现在Singleton类里面存在有构造方法,如果没有明确定义一个构造的话,会自动的在编译时生成一个无参的什么都不做的构造方法,即:一个类至少会保留有一个构造方法。
范例:修改Singleton类定义
class Singleton { private Singleton() { }// 构造方法私有化 public void print() { System.out.println("Hello World!!!"); } }
一旦构造方法私有化了,那么在外部将无法直接通过关键字new来进行对象的实例化操作。
范例:错误的代码
public class Demo { public static void main(String args[]) { Singleton s = null;// 声明对象 s = new Singleton();// 实例化对象 s.print(); } }
对于整个程序到底该如何进行修改,才可以让Demo类里面得到Singleton类实例化对象,并且调用print()方法呢?
分析步骤:
- 构造方法上使用了private声明(private Singleton()),那么就表示这个构造方法只能够被类的内部所使用;
既然如此,可以直接在类的内部实例化一个对象;
class Singleton {
Singleton instance = new Singleton();
private Singleton() {
}// 构造方法私有化
public void print() {
System.out.println("Hello World!!!");
}
}
- 现在的instance在Singleton里面只是一个普通的类属性,而所有的普通类属性必须在类产生实例化对象之后才可以使用,是否存在有一种方式,可以让这个类属性不受Singleton类实例化对象的控制呢?
如果使用static声明instance属性,那么就表示可以在一个类没有产生实例化对象的时候直接使用该属性。
class Singleton {
static Singleton instance = new Singleton();
private Singleton() {
}// 构造方法私有化
public void print() {
System.out.println("Hello World!!!");
}
}
public class Demo {
public static void main(String args[]) {
Singleton s = null;// 声明对象
s = Singleton.instance;// 直接访问static属性
s.print();
}
}
- 在一个类定义的时候应该首先想到的就是类中的属性需要进行封装
private static Singleton instance = new Singleton();
- 而一旦封装之后如果想要访问此属性只能够通过getter方法,那么就需要提供有一个getter方法可以同样不受到Singleton实例化对象的控制,继续使用static属性。
class Singleton { private static Singleton instance = new Singleton(); private Singleton() { }// 构造方法私有化 public void print() { System.out.println("Hello World!!!"); } public static Singleton getInstance() { return instance; } } public class Demo { public static void main(String args[]) { Singleton s = null;// 声明对象 s = Singleton.getInstance();// 直接访问static属性 s.print(); } }
代码意义:
如果说现在要想控制一个类中实例化对象的产生个数,那么首先要锁定的就是类中的构造方法,因为在实例化任何新对象都要使用构造方法,如果构造方法被锁了,那么自然就无法产生新的实例化对象了。
可是既然需要是一个实例化对象,那么就可以在类的内部使用static方式来定义一个公共的对象,并且每一次通过static方法返回唯一的一个对象,这样外部不管有多少次调用,那么最终一个类只能产生唯一的一个对象,这样的设计就属于单例设计模式(Singleton)。
扩展题目:请编写一个Singleton程序,请解释Singleton程序的特点?
class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() { }// 构造方法私有化 public void print() { System.out.println("Hello World!!!"); } public static Singleton getInstance() { return INSTANCE; } } public class Demo { public static void main(String args[]) { Singleton s = Singleton.getInstance(); s.print(); } }
程序特点:构造方法私有化,在类的内部定义static属性与方法,利用static方法取得本类的实例化对象,这样一来不管外部会产生多少个Singleton类的对象,但是本质上永远只有唯一的一个实例化对象。
可是对于单例设计模式有两种形式:饿汉式、懒汉式。
在之前所编写的单例实际上就属于饿汉式的应用,在Singleton类定义的时候就已经准备好了一个Singleton类的实例化对象INSTANCE,而并没有关心这个对象是否使用。
而懒汉式的最大特点就在于它是在第一次使用的时候才进行实例化操作。
范例:实现懒汉式
class Singleton { private static Singleton instance; private Singleton() { }// 构造方法私有化 public void print() { System.out.println("Hello World!!!"); } public static Singleton getInstance() { if (instance == null) {// 此时还没有实例化 instance = new Singleton(); } return instance; } } public class Demo { public static void main(String args[]) { Singleton s = Singleton.getInstance();// 直接访问static属性 s.print(); } }
单例是一个理解过程,核心的一个目的:让一个类在整个系统里面只允许存在有一个实例化对象。
2、多例设计模式
既然存在有单例设计模式,那么就一定会存在有多例设计模式,单例设计只能让一个类产生一个实例化对象,而多例设计可以让一个类产生指定多个实例化对象。
例如:现在要定义一个表示一周时间数的类,这个类只能取七个对象;
范例:定义一个表示性别的类
class Sex { private String title; private static final Sex MALE = new Sex("男"); private static final Sex FEMALE = new Sex("女"); private Sex(String title) { this.title = title; } public String toString() { return this.title; } public static Sex getInatance(int ch) { switch (ch) { case 1: return MALE; case 2: return FEMALE; default: return null; } } } public class Demo { public static void main(String args[]) { Sex sex = Sex.getInatance(2); System.out.println(sex); } }
在JDK 1.7之前,switch只能够利用int或char进行判断,但是正因为如果纯粹是数字或字符意义不明确,所以增加了String的支持。
class Sex {
private String title;
private static final Sex MALE = new Sex("男");
private static final Sex FEMALE = new Sex("女");
private Sex(String title) {
this.title = title;
}
public String toString() {
return this.title;
}
public static Sex getInatance(String ch) {
switch (ch) {
case "man":
return MALE;
case "woman":
return FEMALE;
default:
return null;
}
}
}
public class Demo {
public static void main(String args[]) {
Sex sex = Sex.getInatance("man");
System.out.println(sex);
}
}
如果现在不希望使用String在Switch语句(这个习惯不好)上使用,那么可以再引入一个标记的接口。
class Sex {
private String title;
private static final Sex MALE = new Sex("男");
private static final Sex FEMALE = new Sex("女");
private Sex(String title) {
this.title = title;
}
public String toString() {
return this.title;
}
public static Sex getInatance(int ch) {
switch (ch) {
case 1:
return MALE;
case 2:
return FEMALE;
default:
return null;
}
}
}
interface Choose {
public int MAN = 1;
public int WOMAN = 2;
}
public class Demo {
public static void main(String args[]) {
Sex sex = Sex.getInatance(Choose.WOMAN);
System.out.println(sex);
}
}
以上的代码形式如果自己看没有什么问题,但是如果交给其他人使用,那么就看不懂了。