文章目录

  • 封装 - Access Control(访问权限控制)
  • package: the library unit 包,库的单元
  • jar包
  • 使用jar包中的类(import关键字)
  • 使用包中的类两种情况:
  • intellij导入第三方jar包方法
  • import static 直接调用类中的成员变量或方法
  • collision冲突
  • Java access specifiers 权限修饰符
  • private
  • default
  • protected
  • public
  • 类的权限控制 class access
  • 总结 summary


封装 - Access Control(访问权限控制)

访问权限控制主要通过两个点来解决:

  • package包
  • 权限修饰符,如public

库程序员必须同意在修改库中的类时不删除现有方法,因为这会破坏客户端程序员的代码,所以为了客户端程序员,也就是库使用者不受影响。为了解决这个问题,java提供了访问控制,可以让库创建者指定什么是可以访问的,什么是不能访问的。这个访问级别有四个关键字一次是public, protected, package access (which has no keyword), and private
To solve this problem, Java provides access specifiers to allow the library creator to say what is available to the client programmer and what is not. The levels of access control from “most access” to “least access” are public, protected, package access (which has no keyword), and private.
作为一个库创建者,你应当尽可能保持每个都是private,只暴露出少部分必须的方法以供客户端人使用。
As a library designer, you’ll want to keep everything as “private” as possible, and expose only the methods that you want the client programmer to use.
##面向对象三大基石

  • Inheritance 继承,使子类是父类的一种形式,所以子类和父类属于相同类型
  • Encapsulation(data hiding), 通过package对类访问权限控制,和private等关键字来对成员的访问权限实现数据的隐藏,叫做封装。
  • Polymorphism 多态

package: the library unit 包,库的单元

一个包(文件夹)可以包含很多个类比如java.util这个包,他们都在同一个名称空间下。

通常我们的代码在src文件夹为默认包下,则不需要声明包名,但是如果创建了一个子包比如bbb,该包下面的类必须声明package名称( 创建java文件时IDE会自动帮助添加 ),不然该类会报错missing package statement,该包声明必须放在该文件第一行。
这样这个java类文件就在该包的保护下,任何想使用这个java类的人需要导入该包才能获取这个类的使用权限。也就是说要想发布包,则每个文件都要声明package的名称。子包和父包其实是两个完全不同的包。

thinking in java 电子版 thinking for java_java

举个例子如果要使用某个包下的某个类:
我们要使用ArrayList类,一种方式是指定完整的名称来使用:
java.util.ArrayList list = new java.util.ArrayList(); 但是这个太冗余了,我们可以用另一种方式使用import关键字:

import java.util.ArrayList; //导入util包下的ArrayList类

public class SingleImport { 
...
    ArrayList list = new java.util.ArrayList();  
}

package名称都用小写 比如:net.mindview.utility.foibles 每个编译单元(java文件)只包含一个public的类并且要和文件名相同。可以包含任意个非public 的类。

jar包

java的library发布后就生成一个jar文件,简称jar包,我们要使用某个工具类首先要在项目中添加该jar包,然后就可以import该类,然后使用该jar包中的某个工具类了。
The deployment format of a Java library is a JAR file.

jar包类似于zip压缩包,里面包含很多.class文件,有时也包含源文件.java
A JAR file is actually just a ZIP file. It can contain anything - usually it contains compiled Java code (.class), but sometimes also Java sourcecode (.java).

java可以被反编译,将jar包中的.class文件给反编译成java文件。但是如果开发者使用一些方法模糊了他的代码,反编译将可能出现错误。
However, Java can be decompiled - in case the developer obfuscated his code you won’t get any useful class/function/variable names though.

使用jar包中的类(import关键字)

下面我们来说一下如何使用某个工具类,和他的原理。

使用包中的类两种情况:
  1. 在相同包名(文件夹)下:不需要Import关键字,直接使用该类
  2. 如果在不同包下则需要指定classpath路径来定位要import的包:classpath可以包含多个路径

情况2举例:

  • 使用import 导入类:import p1.Test; 该语句表明要导入 p1 包中的 Test 类。但是编译器在哪里找到p1这个包呢?
  • 在导入时,编译器会首先定位查找包的位置
    安装JDK时,我们已经设置了环境变量 CLASSPATH 来指明类库的路径
    比如:它的值为 .;%JAVA_HOME%\lib,而 JAVA_HOME 变量名称为 D:\Program Files\jdk1.7.0_71,所以我们的 CLASSPATH = .;D:\Program Files\jdk1.7.0_71\lib.classclass
  • JVM将依次到下面的路径寻找p1包 Test.class:(因为是运行时调用)
  1. 首先查找当前路径.p1\Test.class("."表示当前路径),当我们导入jar包则当前项目路径下就会存在p1包就可以找到。
  2. 如果当前路径没有则查找我们设置的classpath路径下也就是jdk标准库中寻找 D:\Program Files\jdk1.7.0_71\lib\p1\Test.class 如果在某个路径下找到了所需的类文件,则停止,如果在所有的路径下都未能找到所需的类文件,则编译或运行期间报错。
intellij导入第三方jar包方法

遵循上述实例,不同的编译工具导入jar包方式不同,当然都需要设置路径。所以如果导入到当前项目的lib下,根据classpath的设置会搜索当前目录。intellij导入第三方jar方法

调用的一个例子:
dvr_chinese.java

package dvr_chinese;

public class RouterTest {
    public static int sharedInt = 5;

    public RouterTest(){

    }
    public void testMehtod(){
        System.out.println(sharedInt);
    }
}

Main.java

import dvr_chinese.RouterTest;//先搜索当前路径下drv_chinese包中的类
import java.util.ArrayList;//当前路径下没有,则搜索Classpath也就是jdk标准库路径下的类
import java.util.*; //如果用到该包下的几个类,则用*来表示调用所有的类

public class Main {

    public static void main(String[] args) {
        System.out.println("This is a test for jar to exe!");
        {
            Routing r = new Routing('d');//在相同包(相同文件夹)下不需要Import
            RouterTest rt = new RouterTest();//在不同文件夹下需要import 该类
            rt.testMehtod();
            ArrayList<String> str = new ArrayList<>();//调用java标准库中的类
        }
    }
}
import static 直接调用类中的成员变量或方法

java1.5版本之后,可以使用import static 来直接调用类中的static成员比如成员变量或者方法,而不需要应用类的名称或者对象。
In Java, static import concept is introduced in 1.5 version. With the help of static import, we can access the static members of a class directly without class name or any object.

//要调用所有方法可以用import static net.mindview.util.Print.*
import static net.mindview.util.Print.print;

public class TestMain {
    public static void main(String[] args) {
        print("daf");
    }
}

Print类中print方法是static的,用import static关键字时候可以直接在代码中print()调用此方法,而不需要Print.print()来调用该类中的此方法。

collision冲突

如果要使用a Vector classimport net.mindview.simple.*;import java.util.*; 这两个包中都包含Vector类。
当使用Vector v = new Vector();这句话时,就不能判定使用哪一个包下的,所以这时编译器会抱怨。这时就要指定完整的包名称来使用该类:
java.util.Vector v = new java.util.Vector();

Java access specifiers 权限修饰符

The Java access specifiers are public, protected, default and private .用这些来修饰成员。

尽量把所有的成员变量设置为private。通常我们把包内类和方法都用默认修饰符,因为不需要暴露到外面,只在该包内使用。而如果其他包要使用则需要使用public,这种情况会比较常见。

private

you can’t touch that!
只在该类中可以访问,其他的类都不可以访问,即使在同一个java文件中不同的类,其他类也不能访问。
所以他是属于你自己的,你可以随意修改他,他是你不给外面使用的。他非常重要和常用,尤其是多线程的时候。
尽可能把成员用Private修饰除非你要暴露或其他用。

举例:

public class TestMain {

    public static void main(String[] args) {
        // Sundae x = new Sundae(); 因为构造方法是private所以不能创建该对象
        Sundae x = Sundae.makeASundae();//可以指定初始化对象的方式,只能通过调用方法来创建该对象
    }
}
class Sundae {
//把构造方法设置成private
    private Sundae() {
    }
    static Sundae makeASundae() {
        return new Sundae();
    }
}
default

Package access, 默认为包权限,该包(文件夹)下所有的也就是同一个包下的所有类可以访问默认修饰符成员。
因为相关的类会分配到同一个包下,所以用默认权限可以更方便的访问默认权限成员。defaul权限修饰的成员,是其他客户端程序员看不到的,(因为他们使用你的jar不会和你在同一个包下),所以你可以随意的自己使用。default在同一包下均可见所以同一包下可继承。

protected

inheritance access
protected是用来处理继承的。
对于他的子类,protected修饰的成员,他的子类可以访问(不管是否在同一个包中)。
对于非子类作用和default一样,只在同一个包中可访问,所以他的范围大于default,多了个子类。Accessible to the sub classes regardless of the package; also to the non-subclass (es) within the same package, but not to the non-subclass(s) of the other package(s).

所以protcted修饰的成员可以仅供继承者继承而不能被所有人使用。

因为java类只能用public和default修饰,所以如果要在其他包继承父类,父类必须是public的,而且继承时要import才能使用该类,也就是说只要是使用其他包的类,都要添加import关键字。

protected是继承父类的成员,继承后该类拥有该成员比如变量或者方法。但是创建父类对象来使用父类的protected成员是不允许的,父类的对象只能调用到public修饰的父类成员变量或方法

public

public意味着这个成员可以被任何人使用,也就是说用他来修饰你想暴露给客户端程序员的成员。
When you use the public keyword, it means that the member declaration that immediately follows public is available to everyone, in particular to the client programmer who uses the library.

Access control is often referred to as implementation hiding. Wrapping data and methods within classes in combination with implementation hiding is often called encapsulation.访问控制是实现的隐藏,把数据包装在类中并隐藏叫做封装。所以通过这个机制,你可以告诉客户端程序员什么可以使用,什么不能使用。

系统创建的构造方法默认是public的,而自己定义的构造方法是可以添加其他修饰符的。

类的权限控制 class access

  1. Class类可以由public和default修饰,不能由private和protected修饰,当为default时,表示只供同一个包下的其他类使用。继承重写的方法控制权限不能小于父类的方法,比如protected修饰的方法方法,重写时就不能用default,应该用protected或public比他范围大的修饰符。
  2. 一个java文件下最多有一个public的类且该public的类名要和文件名相同。当然如果不想暴露到外部这个类也可以使用默认权限,这时就只能在该包下使用该类。

总结 summary

控制对成员的访问有两个原因:

  1. 将方法和字段设置为私有对客户端程序员来说是一种服务,因为他们可以很容易地看到哪些对他们来说是重要的,哪些是可以忽略的。它简化了他们对类的理解。
  2. 第二个原因是重要的是,库的设计者可以更改他的内部代码而不影响客户端程序员使用者。The second and most important reason for access control is to allow the library designer to change the internal workings of the class without worrying about how it will affect the client programmer.

所以访问权限控制实际上是库设计者和程序员之间的沟通。
Notice that access control focuses on a relationship—and a kind of communication—between a library creator and the external clients of that library.

所以如果你只是自己工作做一些小的项目,所有的文件都放到默认包下也没问题。
you are writing all the code yourself, or you are working in close quarters with a small team and everything goes into the same package. Default (package) access may be just fine.