Java 访问控制

1.包的概念

1)package

  • 作用:避免类的命名冲突
  • 包名可以有层次结构,类的全称:包名.类名
  • 同包中的类不能同名
  • 建议:包名所有字母都小写
  • package语句必须写在Java源文件的最开始处

定义包名:

package org.apache.commons.lang

  在实际应用中,包的命名常常是多层次的,因为如果各个公司或开发组织的程序员都随心所欲的命名包名的话,依然不能从根本上解决命名冲突的问题,不利于软件的复用。如上案例,org.apache表示公司或组织的信息(是这个公司或组织域名的反写),commons表示项目的名称信息,lang表示模块的名称信息。

2)import

  • 同包中的类可以直接访问
  • 不同包中的类不能直接访问,若想访问有以下两种方式:
      • a.先import后在访问,import 包名.类名——建议
      • b.类的全称,包名.类名——太繁琐,不建议

不同包的两种访问方式:

import org.test.core.Point;
Point p = new Point();
或者
org.test.core.Point p = new org.test.core.Point();

  有时在import语句中也可以使用“*”符号,例如:

import org.test.core.*;

  如上import语句意味着该包中所有类的全称,即在该源文件中,使用所有包名为org.test.core的类都可以仅仅通过类名来访问。需要注意的是,“import 包名.*”语句并不包含该名的子包中的类(比如org.test中的类不包含)。

  Tips:在Eclipse中,可以使用“CTRL+SHIFT+O”自动完成import语句。

 

2.访问控制修饰符

2.1 封装的意义

  • 降低代码出错的可能性,更便于维护
  • 当内部实现细节改变时,只要保证对外的功能定义不变,其他的模块不需要更改

2.2 访问控制修饰符

  • public:公共的,任何类
  • private:私有的,本类
  • protected:受保护的,本类、子类、同包类
  • 默认的:什么也不写,本类、同包类
修饰符 本类 同一个包中的类 子类 其他类
public 可以访问 可以访问 可以访问 可以访问
protected 可以访问 可以访问 可以访问 不能访问
默认 可以访问 可以访问 不能访问 不能访问
private 可以访问 不能访问 不能访问 不能访问

 

 

 

 

 

  注意:类的访问控制修饰符只能是public或默认的,类中的成员变量如上4种都可以。

 

3. static与final

3.1 static:静态的

3.1.1 static修饰成员变量

  static可以修饰成员变量,它所修饰的成员变量不属于对象的数据结构,而是属于类的变量,通常通过类名来引用static成员。当创建对象后,成员变量存储在堆中,而static成员变量和类的信息一起存储在方法区中,一个类的static成员变量只有“一份”(存储在方法区中),无论该类创建了多少对象。

1)静态变量:

  1.1)由static修饰的

  1.2)属于类的,存在方法区中,只有一份

  1.3)常常通过类名.变量来访问

  1.4)何时用:所有对象所共享的数据(图片、音频、视频等)

 

案例1:static修饰成员变量

public class StaticVarDemo {
	public static void main(String[] args){
		Student s1 = new Student(2);
		Student s2 = new Student(3);
//		s1.age = 5;  编译错误,private修饰,无法访问
	}
}
class Student{
	private int age;
	private static int numOfStudent;
	public Student(int age){
		this.age = age;
		System.out.println(++numOfStudent);
	}
}

以上代码运行结果:

1
2

以上运行结果分析:如上代码,声明两个Student类对象后,numOfStudent的值为2。当声明第一个Student类对象后,numOfStudent值增1变为1(默认为0),声明第二个Student对象后,因为numOfStudent存在方法区中只有一份,所以其值在刚刚的1的基础上变为2。

 

3.1.2 static修饰方法

  通常的方法都会涉及到对具体对象的操作,这些方法在调用时,需要隐式的传递对象的引用(this),而static修饰的方法则不需要对某些对象进行操作,其运行结果仅仅与输入的参数有关,调用时直接类名引用即可,如下代码:

double c = Math.sqrt(3.0*3.0);

  上面的方法在调用时,没有隐式的传递对象引用,因此在static方法中是不可以使用this关键字的。另外,由于static在调用时没有具体的对象,因此在static方法中不能对非static成员(对象成员)进行访问。

  static方法的作用在于提供一些“工具方法”和“工厂方法”等,如下的一些工具方法,只是完成某一功能,不需要传递this。

RandomUtils.nextInt()
StringUtils.leftPad(String str,int size,char padChar)

 

2)静态方法:

  2.1)由static修饰的

  2.2)属于类的,存在方法区中,只有一份

  2.3)常常通过类名.方法来访问

  2.4)静态方法没有隐式的this传递,静态方法中不能直接访问实例成员

  2.5)何时用:方法的操作仅与参数相关而与对象无关

 

3.1.3 static块

  static块为属于类的代码块,在类加载期间执行的代码块,只执行一次,可以用来在软件中还在静态资源(图像、音频等)。

 

案例2:静态块演示

public class StaticBlockDemo {
	public static void main(String[] args){
		Foo foo = new Foo();
	}
}
class Foo{
	public Foo(){
		System.out.println("Foo()");
	}
	static{
		//类加载期间,只执行一次
		System.out.println("Load Foo.class");
	}
}


/*
运行结果:
Load Foo.class
Foo()
 */

  在Foo类加载时,先运行静态块,而后执行构造方法,即:static块是在创建对象之前执行的。

 

3)静态块:

  3.1)属于类的,在类被加载期间自动执行,因为类只被加载一次,所以静态块也只执行一次

  3.2)何时用:初始化/加载静态资源(图片、音频、视频等)

 

3.2 final:最终的、不可变的

  • 修饰变量:变量不能被改变
  • 修饰方法:方法不能被重写
  • 修饰类:类不能被继承

3.2.1 final修饰变量

  final关键字修饰变量,意为不可改变的,final可以修饰成员变量,也可以修饰局部变量,当final修饰成员变量时,可以有两种初始化方式:

  1. 声明同时初始化
  2. 构造函数中初始化

  final关键字修饰局部变量,在使用之前初始化即可。

public class FinalVarDemo {
	private final int no=100;  //final成员变量声明时初始化
	public static void main(String[] args){
//		no = 99;  编译错误,因为final变量不可被改变
	}
}

  

3.2.2 final修饰方法

  final关键字修饰方法不可以被重写,使一个方法不能被重写的意义在于:防止子类在定义新方法时造成的“不经意”重写,如下案例。

class Car{
	//点火
	public void fire(){...}
}
class Tank extends Car{
	//开炮
	public void fire(){...}
}

  为避免上述情况,可以将Car类方法声明为final的,这样该方法就不能被子类重写。

class Car{
	//点火
	public final void fire(){}
}
class Tank extends Car{
	//开炮
//	public void fire(){}  编译错误,不能被重写
}

  

3.2.3 final修饰类

  final关键字修饰的类不可以被继承。使一个类不能被继承的意义在于:可以保护类不被继承修改,可以控制滥用继承对系统造成的危害。在JDK中的一些基础类库被定义为final的,如:String、Math、Integer、Double等。自己定义的类也可以声明为final的。

final class Foo{}
class Goo extends Foo{}  //编译错误,final修饰的类不可以被继承

  

3.3 static final常量

  • 必须声明同时初始化
  • 通过类名来访问,不能被改变
  • 常量名所有的字母都大写,多个单词用_分隔(如STUDENT_NAME)
  • 编译器在编译时会将常量直接替换为具体的值,效率高
public class FinalFunctionDemo {
	public static void main(String[] args){
		System.out.println(Soo.NUM);   //使用类名. 来访问
		//代码编译时,会替换为:System.out.println(100);
	}
}

class Soo{
	public static final int NUM=100;
}


//运行结果:100

  

4. 案例演示

案例3:final演示

//演示final修饰变量
/*
 * final 修饰成员变量,只有两种初始化方法:
 * 1)声明的同时初始化
 * 2)在构造方法中初始化
 * final修饰局部变量,只要在用之前初始化即可
 */
class Aoo{
	final int a = 5;
	final int b;
	Aoo(){
		b = 6;
	}
	void show(){
		final int c;
//		a = 55; //编译错误,final的变量不可被改变
	}
}

//演示final修饰方法
class Boo{
	final void show(){}
	void say(){}
}
class Coo extends Boo{
//	void show(){}  //编译错误,final修饰的方法不能被重写
	void say(){}
}

//演示final修饰类
final class Doo{

}
//class Eoo extends Doo{}  //编译错误,final修饰的类不能被继承
class Foo{}
final class Goo extends Foo{} //final修饰的类可以继承别的类

 

案例4:static演示

public class StaticDemo {
	public static void main(String[] args){
		Joo o1 = new Joo();
		o1.show();
		/*
		输出:
		a=1
		b=1
		*/
		
		Joo o2 = new Joo();
		o2.show();
		System.out.println("Joo.b="+Joo.b);  //建议类名. 来访问
		System.out.println("o1.b="+o1.b);    //不建议
		System.out.println("o2.b="+o2.b);     //不建议
		/*
		 *输出:
		 *a=1
		 *b=2
		 *Joo.b=2
		 *o1.b=2
		 *o2.b=2
		*/
		
		Koo.test();
		/*
		 * 输出:
		 * 0
		 */
		
		Loo o3 = new Loo();
		Loo o4 = new Loo();
		/*
		 * 输出:
		 * 静态块 //静态块只执行一次
		 *构造方法
		 *构造方法
		 */
	}
}
class Loo{  //演示静态块
	static{
		System.out.println("静态块");
	}
	Loo(){
		System.out.println("构造方法");
	}
}

class Koo{  //演示静态方法
	int a;
	static int b;
	void show(){   //有隐式this
		System.out.println(a);   //this.a
		System.out.println(b);   //Koo.b
	}
	static void test(){  //没有隐式this
		/*没有this意味着没有对象,而实例成员必须通过对象. 来访问
		所以静态方法中不能直接访问实例成员
		System.out.println(a);  编译错误
		*/
		System.out.println(b);  //Koo.b
	}
}
class Joo{  //演示静态变量
	int a;  //实例变量
	static int b;  //静态变量
	Joo(){
		a++;
		b++;
	}
	void show(){
		System.out.println("a="+a);
		System.out.println("b="+b);
	}
}

/*
输出结果:
a=1
b=1
a=1
b=2
Joo.b=2
o1.b=2
o2.b=2
0
静态块
构造方法
构造方法
*/

  

案例5:static final的演示

public class StaticFinalDemo {
	public static void main(String[] args){
		System.out.println(Hoo.PI);  //3.14  通过类名点 来访问
//		Hoo.PI = 3.1415926; //编译错误,常量不能被改变
		
		Ioo o1 = new Ioo();
		o1.count = 50;
		Ioo o2 = new Ioo();
		System.out.println(o2.count);  //50 静态变量只有一份
		
		/*
		 * 1)加载Ioo.class到方法区中
		 * 2)静态变量count存储到方法区中
		 * 3)到方法区中获取count并输出
		 */
		System.out.println(Ioo.count);
		
		/*
		 * 编译器在编译时会将常量直接替换为具体的值---效率高
		 */
		System.out.println(Ioo.NUM);  //5
	}
}
class Ioo{
	public static final int NUM = 5; //常量
	public static int count = 5;  //静态变量
}
class Hoo{
	public static final double PI = 3.14;
	public static final int DOUBLE_NUM = 5;
//	public static final int NUMBER; //编译错误,常量必须声明并初始化
}

 

  

 

 

 

 

posted @ 2017-06-14 00:27  将暮未暮  阅读(406)  评论(0编辑  收藏  举报