在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。java
封装能够被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。shell
要访问该类的代码和数据,必须经过严格的接口控制。编程
封装最主要的功能在于咱们能修改本身的实现代码,而不用修改那些调用咱们代码的程序片断。windows
适当的封装可让程式码更容易理解与维护,也增强了程式码的安全性。安全
1. 良好的封装可以减小耦合。编程语言
2. 类内部的结构能够自由修改。ide
3. 能够对成员变量进行更精确的控制。函数
4. 隐藏信息,实现细节。测试
1. 修改属性的可见性来限制对属性的访问(通常限制为private),例如: public class Person { private String name; private int age; } 这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其余类都访问不了,如此就对信息进行了隐藏。 2. 对每一个值属性提供对外的公共方法访问,也就是建立一对赋取值方法,用于对私有属性的访问,例如: public class Person{ private String name; private int age; public int getAge(){ return age; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public void setName(String name){ this.name = name; } } 采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
让咱们来看一个java封装类的例子:this
EncapTest.java 文件代码: /* 文件名: EncapTest.java */ public class EncapTest{ private String name; private String idNum; private int age; public int getAge(){ return age; } public String getName(){ return name; } public String getIdNum(){ return idNum; } public void setAge( int newAge){ age = newAge; } public void setName(String newName){ name = newName; } public void setIdNum( String newId){ idNum = newId; } } 以上实例中public方法是外部类访问该类成员变量的入口。 一般状况下,这些方法被称为getter和setter方法。 所以,任何要访问类中私有成员变量的类都要经过这些getter和setter方法。 经过以下的例子说明EncapTest类的变量怎样被访问: RunEncap.java 文件代码: /* F文件名 : RunEncap.java */ public class RunEncap{ public static void main(String args[]){ EncapTest encap = new EncapTest(); encap.setName("James"); encap.setAge(20); encap.setIdNum("12343ms"); System.out.print("Name : " + encap.getName()+ " Age : "+ encap.getAge()); } } 以上代码编译运行结果以下: Name : James Age : 20
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口一般以interface来声明。一个类经过继承接口的方式,从而来继承接口的抽象方法。
接口并非类,编写接口的方式和类很类似,可是它们属于不一样的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,不然该类要定义接口中的全部方法。
接口没法被实例化,可是能够被实现。一个实现接口的类,必须实现接口内所描述的全部方法,不然就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们能够成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口的声明语法格式以下:
[可见度] interface 接口名称 [extends 其余的接口名名] { // 声明变量 // 抽象方法 } Interface关键字用来声明一个接口。下面是接口声明的一个简单例子。 NameOfInterface.java 文件代码: /* 文件名 : NameOfInterface.java */ import java.lang.*; //引入包 public interface NameOfInterface { //任何类型 final, static 字段 //抽象方法 }
接口有如下特性:
实例 Animal.java 文件代码: /* 文件名 : Animal.java */ interface Animal { public void eat(); public void travel(); }
当类实现接口的时候,类要实现接口中全部的方法。不然,类必须声明为抽象的类。
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
实现一个接口的语法,可使用这个公式:...implements 接口名称[, 其余接口名称, 其余接口名称..., ...] ...
实例 MammalInt.java 文件代码: /* 文件名 : MammalInt.java */ public class MammalInt implements Animal{ public void eat(){ System.out.println("Mammal eats"); } public void travel(){ System.out.println("Mammal travels"); } public int noOfLegs(){ return 0; } public static void main(String args[]){ MammalInt m = new MammalInt(); m.eat(); m.travel(); } } 以上实例编译运行结果以下: Mammal eats Mammal travels
重写接口中声明的方法时,须要注意如下规则:
在实现接口的时候,也要注意一些规则:
一个接口能继承另外一个接口,和类之间的继承方式比较类似。接口的继承使用extends关键字,子接口继承父接口的方法。
下面的Sports接口被Hockey和Football接口继承:
// 文件名: Sports.java public interface Sports { public void setHomeTeam(String name); public void setVisitingTeam(String name); } // 文件名: Football.java public interface Football extends Sports { public void homeTeamScored(int points); public void visitingTeamScored(int points); public void endOfQuarter(int quarter); } // 文件名: Hockey.java public interface Hockey extends Sports { public void homeGoalScored(); public void visitingGoalScored(); public void endOfPeriod(int period); public void overtimePeriod(int ot); } Hockey接口本身声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类须要实现六个方法。 类似的,实现Football接口的类须要实现五个方法,其中两个来自于Sports接口。
在Java中,类的多继承是不合法,但接口容许多继承。
在接口的多继承中extends关键字只须要使用一次,在其后跟着继承接口。 以下所示:
public interface Hockey extends Sports, Event
以上的程序片断是合法定义的子接口,与类不一样的是,接口容许多继承,而 Sports及 Event 可能定义或是继承相同的方法
最经常使用的继承接口是没有包含任何方法的接口。
标记接口是没有任何方法和属性的接口.它仅仅代表它的类属于一个特定的类型,供其余代码来测试容许作一些事情。
标记接口做用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义以下:
package java.util; public interface EventListener {}
没有任何方法的接口被称为标记接口。标记接口主要用于如下两种目的:
正如EventListener接口,这是由几十个其余接口扩展的Java API,你可使用一个标记接口来创建一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
这种状况是标记接口最初的目的,实现标记接口的类不须要定义任何接口方法(由于标记接口根本就没有方法),可是该类经过多态性变成一个接口类型。
为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。
一、把功能类似或相关的类或接口组织在同一个包中,方便类的查找和使用。
二、如同文件夹同样,包也采用了树形目录的存储方式。同一个包中的类名字是不一样的,不一样的包中的类的名字是能够相同的,当同时调用两个不一样包中相同类名的类时,应该加上包名加以区别。所以,包能够避免名字冲突。
三、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。
包语句的语法格式为:package pkg1[.pkg2[.pkg3…]];
例如,一个Something.java 文件它的内容 package net.java.util; public class Something{ ... }
那么它的路径应该是 net/java/util/Something.java 这样保存的。 package(包) 的做用是把不一样的 java 程序分类保存,更方便的被其余 java 程序调用。
一个包(package)能够定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。
如下是一些 Java 中的包:
开发者能够本身把一组类和接口等打包,并定义本身的包。并且在实际开发中这样作是值得提倡的,当你本身完成类的实现以后,将相关的类分组,可让其余的编程者更容易地肯定哪些类、接口、枚举和注释等是相关的。
因为包建立了新的命名空间(namespace),因此不会跟其余包中的任何名字产生命名冲突。使用包这种机制,更容易实现访问控制,而且让定位相关类更加简单。
建立包的时候,你须要为这个包取一个合适的名字。以后,若是其余的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。
包声明应该在源文件的第一行,每一个源文件只能有一个包声明,这个文件中的每一个类型都应用于它。
若是一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。
例子 让咱们来看一个例子,这个例子建立了一个叫作animals的包。一般使用小写的字母来命名避免与类、接口名字的冲突。 在 animals 包中加入一个接口(interface): Animal.java 文件代码: /* 文件名: Animal.java */ package animals; interface Animal { public void eat(); public void travel(); } 接下来,在同一个包中加入该接口的实现: MammalInt.java 文件代码: package animals; /* 文件名 : MammalInt.java */ public class MammalInt implements Animal{ public void eat(){ System.out.println("Mammal eats"); } public void travel(){ System.out.println("Mammal travels"); } public int noOfLegs(){ return 0; } public static void main(String args[]){ MammalInt m = new MammalInt(); m.eat(); m.travel(); } } 而后,编译这两个文件,并把他们放在一个叫作animals的子目录中。 用下面的命令来运行: $ mkdir animals $ cp Animal.class MammalInt.class animals $ java animals/MammalInt Mammal eats Mammal travel
为了可以使用某一个包的成员,咱们须要在 Java 程序中明确导入该包。使用 "import" 语句可完成此功能。
在 java 源文件中 import 语句应位于 package 语句以后,全部类的定义以前,能够没有,也能够有多条,其语法格式为:
import package1[.package2…].(classname|*);
若是在一个包中,一个类想要使用本包中的另外一个类,那么该包名能够省略。
例子 下面的 payroll 包已经包含了 Employee 类,接下来向 payroll 包中添加一个 Boss 类。Boss 类引用 Employee 类的时候能够不用使用 payroll 前缀,Boss类的实例以下。 Boss.java 文件代码: package payroll; public class Boss { public void payEmployee(Employee e) { e.mailCheck(); } } 若是 Boss 类不在 payroll 包中又会怎样?Boss 类必须使用下面几种方法之一来引用其余包中的类。 使用类全名描述,例如: payroll.Employee 用 import 关键字引入,使用通配符 "*" import payroll.*; 使用 import 关键字引入 Employee 类: import payroll.Employee; 注意: 类文件中能够包含任意数量的 import 声明。import 声明必须在包声明以后,类声明以前。
类放在包中会有两种主要的结果:
下面是管理你本身 java 中文件的一种简单方式: 将类、接口等类型的源码放在一个文本中,这个文件的名字就是这个类型的名字,并以.java做为扩展名。例如: // 文件名 : Car.java package vehicle; public class Car { // 类实现 } 接下来,把源文件放在一个目录中,这个目录要对应类所在包的名字。 ....\vehicle\Car.java 如今,正确的类名和路径将会是以下样子: 类名 -> vehicle.Car 路径名 -> vehicle\Car.java (在 windows 系统中) 一般,一个公司使用它互联网域名的颠倒形式来做为它的包名.例如:互联网域名是 runoob.com,全部的包名都以 com.runoob 开头。包名中的每个部分对应一个子目录。 例如:有一个 com.runoob.test 的包,这个包包含一个叫作 Runoob.java 的源文件,那么相应的,应该有以下面的一连串子目录: ....\com\runoob\test\Runoob.java 编译的时候,编译器为包中定义的每一个类、接口等类型各建立一个不一样的输出文件,输出文件的名字就是这个类型的名字,并加上 .class 做为扩展后缀。 例如: // 文件名: Runoob.java package com.runoob.test; public class Runoob { } class Google { } 如今,咱们用-d选项来编译这个文件,以下: $javac -d . Runoob.java 这样会像下面这样放置编译了的文件: .\com\runoob\test\Runoob.class .\com\runoob\test\Google.class 你能够像下面这样来导入全部 \com\runoob\test\ 中定义的类、接口等: import com.runoob.test.*; 编译以后的 .class 文件应该和 .java 源文件同样,它们放置的目录应该跟包的名字对应起来。可是,并不要求 .class 文件的路径跟相应的 .java 的路径同样。你能够分开来安排源码和类的目录。 <path-one>\sources\com\runoob\test\Runoob.java <path-two>\classes\com\runoob\test\Google.class 这样,你能够将你的类目录分享给其余的编程人员,而不用透露本身的源码。用这种方法管理源码和类文件可让编译器和java 虚拟机(JVM)能够找到你程序中使用的全部类型。 类目录的绝对路径叫作 class path。设置在系统变量 CLASSPATH 中。编译器和 java 虚拟机经过将 package 名字加到 class path 后来构造 .class 文件的路径。 <path- two>\classes 是 class path,package 名字是 com.runoob.test,而编译器和 JVM 会在 <path-two>\classes\com\runoob\test 中找 .class 文件。 一个 class path 可能会包含好几个路径,多路径应该用分隔符分开。默认状况下,编译器和 JVM 查找当前目录。JAR 文件按包含 Java 平台相关的类,因此他们的目录默认放在了 class path 中。
用下面的命令显示当前的CLASSPATH变量:
删除当前CLASSPATH变量内容:
设置CLASSPATH变量: