封装、访问控制符与包及两种导入

来源:互联网 发布:sketch windows版 编辑:程序博客网 时间:2024/06/02 10:12


1.封装

1)如果没有封装

如果没有封装,就可能出现虽然语法正常却不合乎常理的事情。如下代码:
public class Person {public String name;public int age;}public class PersonTest{public static void main(String[] args){Person person = new Person();person.name = "tad";person.age = 10000;System.out.println(person.name + ";" +person.age);}}
上面代码,虽然没有语法错误,但是Person的age却可以随便指定,甚至可以变为负数,在Java语法上,这是没有错误的,但是与常理却极其不符,正是基于此,封装是非常有必要的,正是基于此Java推荐将类属性进行封装。

2)封装定义

封装(Encapsulation)面向对象的四大(注:抽象、封装、继承、多态)特性之一,指的是对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过类所提供的方法来实现对内部信息的访问与操作。

3)封装意义

(1)隐藏类实现细节
(2)类使用者只可以通过事先预定方法访问属性,从而可以在访问方法加入控制逻辑,限定对属性不合理访问。
(3)进行数据检查,利于保证对象信息完整性。
(4)便于修改,提高代码的可维护性。

4)封装要点

(1)把类的属性与实现细节隐藏,不允许外部直接访问。
(2)把类的方法暴露,让方法控制对属性的安全访问与操作。
(3)一个常常就是一个小的模块,设计时只让这个模块公开必须让外界知道的内容,而隐藏其它一切内容。模块设计追求高内聚(尽可能把模块的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部干预)、低耦合(仅暴露少量方法给外部)。
一句话总结:该藏的藏,该露的露。

2.访问控制符

上面说的封装是OO中普遍的概念,对于其在面向对象的语言都是有特定关键字来实现的,Java提供3个控制符(private、protected、public),外加没有访问控制符,共同构成了4个访问级别,以此来完成Java的封装功能。

1)访问控制级别排序


2)4访问控制符详解-外部类成员级别

(1)private

当前类访问权限,如果类成员(属性、方法、构造器等)使用private访问控制符修饰,则该成员只能在当前类内部被访问。显然,此访问修饰符用于修改属性最合适,可以把属性隐藏到类内部。
注:如果字段被private修饰,那么如果该字段想要被外部访问就必须提供其setter与getter方法。此处两点需要掌握:1.如果类中包含有xxx的属性,则其对应的getter与setter方法应该为getXxx()与setXxx(),即将原来字段名首字母大写并在前面增加get与set动词,变成getter与setter方法;2.如果一个Java类的每个字段都被private修饰,并为每个字段提供了public修饰的getter与setter方法,那么此类符合JavaBean规范,JavaBean总是封装良好的类。

(2)default

包访问权限,如果类成员(属性、方法、构造器)无访问修饰符修饰,则它具有包访问权限,default修饰的类成员可以被相同包下的其它类访问到。

(3)protected

子类访问权限,如果类成员(属性、方法、构造器)被protected控制符修饰,那么该成员即可以被同一包中其它类访问,同时外加被不同包的子类访问。通常情况下,如果使用protected修饰方法,通常是希望子类来重写此方法。

(4)public

公共访问权限,最宽松的访问控制级别,如果类成员(属性、方法、构造器等)被public修饰,那么此成员可以被任何类访问到,不管访问类与被访问类是否同一包、是否有继承关系。

(5)终级表格


注:访问控制符用于控制类成员是否可以被其它类访问,对于局部变量面言,其作用域是其所在方法,不可能被其它类访问,因此不可被其它类访问到。

(6)Person类案例

public class Person {//private修饰只能被本类成员,达到封装效果private String name;private int age;//name的getter方法public String getName() {return name;}//name的setter方法public void setName(String name) {this.name = name;}//age的getter方法public int getAge() {return age;}//age的setter,在此进行数据检查,保证对象完整性public void setAge(int age) {if(age >= 125 || age < 0){throw new IllegalArgumentException("Illegal age provided!");}this.age = age;}}public class PersonTest{public static void main(String[] args){Person person = new Person();person.setName("Tad");person.setAge(23);System.out.println(person.getName() + ";" +person.getAge());}}

3)default与public详解-接口成员级别

(1)default


(2)public


4)default与public详解-外部类与接口级别

对于外部类,也可以使用访问级别,但只可以使用两种访问级别,public与default,而不可以使用protected和private,原因是外部类没有处于任何类的内部,也就没有其所在类的内部、所在类的子类两个范围,从而private和protected没有意义。

(1)default

default修饰的类只能被相同包的其它类进行访问。

(2)public

被public修饰的外部类可以被所有类进行访问,如声明变量、创建实例。

注:如果一个Java源文件定义的类没有被public修饰,则该源文件的文件名可以是一切合法文件名;但如果Java源文件中定义了public修饰的类,则该源文件名必须与public修饰的类的类名相同;综合上述,一个源文件中不可以有两个public修饰的类。

4)访问控制符使用原则

(1)类里绝大多数字段都应该使用private修饰,只有一个static修饰的或类似全局变量的字段才可以被public修饰;除此之外,有些方法只用于辅助实现该类的其它方法(工具方法),这些方法也应该使用private修饰。
(2)如果某个类主要用做其他类的父类,该类里包含的大部分方法仅希望被其子类重写,而不想被外界调用,则应该使用protected修饰。
(3)希望暴露给其他类自由调用的方法应该使用public修饰,因为类的构造器通过使用public修饰,从而允许其它地方创建该类的实例。因为外部类通常希望被其它类自由使用,所以大部分外部类使用public修饰。

3.包

1)包原因

前面控制的访问控制符的控制范围好多是与包范围相关的,包产生的原因如下,JDK及Java软件开发商在开发软件时不可避免的需要开发大量类、接口、枚举等程序组件,当大量的类的组合在一起时,不可避免的就是涉及到重名的问题,如java.util.Date是一个日期类,而java.sql.Date也是日期类,如果两个类不在不同的包内,那么肯定就会造成类名冲突。正是基于此Java引入包机制,提供类的多层命令,解决类命令冲突与类文件管理问题,如同C#中命名空间。

2)包语法与命名规范

(1)包语法package

package语句必须作为源文件的第一条非注释性语句;一个源文件只能指定一个包,即只能包含一条package语句;该源文件可以定义多个类则这些类全部位于该包下;如果没有显式指定package语句,则处于默认包下,但注意在真正的开发中几乎不会把类、接口定义在默认包下
//第一句非注释性语句package me.tad.javase.oo;public class Hello {public static void main(String[] args) {System.out.println("Hello World");Hi.sayHi();}}class Hi{public static void sayHi(){System.out.println("Hi");}}

(2)包命名规范

①Java语法只要求包名是有效的标识符即可,但是从可读性规范解译,包名应该全部是小写字母,并且应该由一个或多个有意义的单词连接而成。
为防止可能出现包名冲突问题,通常把包命令为公司域名倒序形式,如com.baidu包及其子包下,在真正的实际开发中,如果公司下面还有其它项目,那么还最好com.baidu下建立项目子包,如com.baidu.newsapp;如果此项目还很大有很多模块,则②需要在项目子包下建立模块子包,如com.baidu.newsapp.connectors;如果该模块也很大,需要建立多个组件,此时需要在模块下以组件名再次建立子包,以此类推。
③除非在真的需要的情况,不要建立太多包,尽量不要发生一个包中只有一个类的情况,那样反而增加了类的管理难度。

3)包访问

①同一个包中的类可以自由访问,如上面示例,Hello与Hi类位于同一个包中,所以可以直接访问;
②如果不在同一包中,需要使用包前缀+类名方式访问。如下例:
package me.tad.javase.packtest;public class Hi {public static void sayHi(){System.out.println("Hi");}}/*****另一个类*****///第一句非注释性语句package me.tad.javase.oo;public class Hello {public static void main(String[] args) {System.out.println("Hello World");me.tad.javase.packtest.Hi.sayHi();}}
③现在特殊情况,如果两个包为父包与子包关系,则在父包类中访问子包时,需要写类的全类名(全部包名+类名),而不是省略父包部分,虽然父子包之间确实存在某种内存的逻辑关系,但它们在用法则不存在任何关系。
package me.tad.javase.oo.encapsulation;public class Hi {public static void sayHi(){System.out.println("Hi");}}/*另一个类*/package me.tad.javase.oo;public class Hello {public static void main(String[] args) {System.out.println("Hello World");//下面会报语法错误//encapsulation.Hi.sayHi();me.tad.javase.oo.encapsulation.Hi.sayHi();}}
④如果创建其它包类的实例,则在调用构造器时也需要使用包前缀,如下:
package me.tad.javase.oo;public class Hello {public static void main(String[] args) {me.tad.javase.packtest.Hi hi = new me.tad.javase.packtest.Hi();hi.sayHi();}}

4)JDK常用包

Java核心类都放在java包的子包下;Java的许多扩展类都放在javax包(x为extension)的子包下,按功能进行的子包划分。
java.lang:其中lang为language,这个包下放着java语言的核心类,如String、Thread、System、Runtime等与Java语言运行息息相关的类,此包特点是使用该包下的类无须使用import语句导入,系统会自动加载此包下所有类。
java.util:此包包含了java大量工具类、接口以及大名鼎鼎地集合框架,如Date、List、ArrayList等。
java.net:包含与java网络编程相关的类和接口。
java.io:包含与java输入、输出相关类和接口
java.text:包含与java格式化相关类和接口
java.sql:包含与JDBC数据库编程相关类和和接口
java.awt:包含抽象工具集(Abstract Window Toolkit)相关的类与接口中,主要用于构建GUI程序。
javax.swing:包含与Swing图形用户界面编程相关类、接口,用于构建平台无关的GUI程序。

4.导入

1)import


(1)import语法

上面的包访问方式是非常繁琐的,为简化编程,Java中引入import关键字。
import可以向某个java文件中导入指定包层次下某个类或全部类;import应该出现在package语句之后与类定义之前;一个源文件只能包含一个package,但可以包含多个import语句。

import既可以指定导入一个类;也可以指定某个包下所有类,当导入全部类时,需要使用到*,此*只能代表表,不能代表包,也就是说该包下的子包不会被连带导入。
//导入一个类import java.util.ArrayList;//导入java.util下的所有类、接口import java.util.*;

一旦使用import导入指定类后,源文件中就可以直接使用,而不需要编写全类名。如下:
package me.tad.javase.oo;import me.tad.javase.packtest.Hi;public class Hello {public static void main(String[] args) {Hi hi = new Hi();hi.sayHi();}}

(2)import三点注意

①import可以简化编程,但不是必须的,只要不怕麻烦写全类名。
②java默认所有源文件中导入java.lang包下所有类,因为此使用String、System、Math等类可以直接使用,而不需要导包。
③当源文件中,出现两个不同包中相同类名的类时,就必须使用全类名,如JDBC编程时,java.util.Date与java.sql.Date,此时就必须使用全类名,因为如果只写类名,编译器已经迷茫。
java.util.Date date = new java.util.Date();java.sql.Date sqlDate = new java.sql.Date(1000);

2)import static-静态导入

JDK1.5之后增加了静态导入,所谓静态导入就是导入指定类的某个静态字段、方法或者该类的全部静态字段与方法。

(1)语法

//静态导入某个静态字段或方法import static package.subpackage...ClassName.fieldName|methodName;//静态导入全部静态字段与方法import static package.subpackage...ClassName.*;
此处*又只能代表静态字段或方法名。

(2)位置

与import一样,也放在package语句之后、类定义之前,而import static与import两者之间没有任何顺序,不过习惯import static放在import之后。

(3)import与import static

import省略的是包名,import static不但省略包名还省略类名。
import与import static都是可以简化代码量,只是两者导入目标是不一样的,前者是导入的类,后者导入的是静态字段与方法。

package me.tad.javase.oo;import static java.lang.Math.*;public class StaticImport {public static void main(String[] args){System.out.println(PI);}}

0 0
原创粉丝点击