详解java中import的作用

一、package

C/C++ 的 #include会把所包含的内容在编译时添加到程序文件中,而java的import则不同。

这里我们先了解一下Java 的 package 到底有何用处。

package名称就像是我们的姓,而class名称就像是我们的名字 。package和package的附属关系用"."来连接,这就像是复姓。比如说 java.lang.String就是复姓 java.lang,名字為 String 的类别;java.io.InputStream 则是复姓 java.io,名字為 InputStream的类别。

Java 会使用 package 这种机制的原因也非常明显,就像我们取姓名一样 ,光是一间学校的同一届同学中,就有可能会出现不少同名的同学,如果不取姓的话,那学校在处理学生资料,或是同学彼此之间的称呼,就会发生很大的困扰。相同的,全世界的 Java 类数量,恐怕比日本人还多,如果类别不使用package名称,那在用到相同名称的不同类时, 就会产生极大的困扰。所以package这种方式让极大降低了类之间的命名冲突。

Java 的package名称我们可以自己取,不像人的姓没有太大的选择 ( 所以出现很多同名同姓的情况 ),如果依照 Sun 的规范来取套件名称,那理论上不同人所取的套件名称不会相同 ( 需要的话请参阅 “命名惯例” 的相关文章 ),也就不会发生名称冲突的情况。

可是现在问题来了,因為很多package的名称非常的长,在编程时,要使用一个类要将多个包名.类名完全写出,会让代码变得冗长,减低了简洁度。例如

java.io.InputStream is = java.lang.System.in;
java.io.InputStreamReader isr= new java.io.InputStreamReader(is);
java.io.BufferedReader br = new java.io.BufferedReader(isr);

显得非常麻烦,于是Sun公司就引入了import。

二、import

import就是在java文件开头的地方,先说明会用到那些类别。
接着我们就能在代码中只用类名指定某个类,也就是只称呼名字,不称呼他的姓。

首先,在程序开头写:

import java.lang.System;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;

于是我们就可以在程序中这样写到:

InputStream = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);

一个java文件就像一个大房间,我们在门口写着在房间里面的class的姓和名字,所以在房间里面提到某个class就直接用他的名字就可以。例如:

System 就是指 java.lang.System,而 InputStream 就是指 java.io.InputStream。

但是如果一个java文件里面有多个同个“姓”,即包名相同的类(例如上面的InputStream,InputStreamReader,BufferedReader都是java.io中的类),我们一一写出显得比较繁杂,所以Sun就让我们可以使用

import java.lang.*;
import java.io.*;

表示文件里面说到的类不是java.lang包的就是java.io包的。编译器会帮我们选择与类名对应的包。

那我们可不可以再懒一点直接写成下面声明呢?

import java.*;

历史告诉我们,这样是不行的。因為那些类别是姓 java.io 而不是姓 java。就像姓『诸葛』的人应该不会喜欢你称他為『诸』 先生吧。这样写的话只会将java包下的类声明,而不不会声明子包的任何类。

这里注意,java.lang包里面的类实在是太常太常太常用到了,几乎没有类不用它的, 所以不管你有没有写 import java.lang,编译器都会自动帮你补上,也就是说编译器只要看到没有姓的类别,它就会自动去lang包里面查找。所以我们就不用特别去 import java.lang了。

一开始说 import 跟 #include 不同,是因为import 的功能到此為止,它不像#include 一样,会将其他java文件的内容载入进来。import 只是让编译器编译这个java文件时把没有姓的类别加上姓,并不会把别的文件程序写进来。你开心的话可以不使用import,只要在用到类别的时候,用它的全部姓名来称呼它就行了(就像例子一开始那样),这样跟使用import功能完全一样。

三、import的两种导入声明

  • 单类型导入(single-type-import)(例:import java.util.ArrayList; )
  • 按需类型导入(type-import-on-demand)(例:import java.util.*;)

有如下属性:

  1. java以这样两种方式导入包中的任何一个public的类和接口(只有public类和接口才能被导入)
  2. 上面说到导入声明仅导入声明目录下面的类而不导入子包,这也是为什么称它们为类型导入声明的原因。
  3. 导入的类或接口的简名(simple name)具有编译单元作用域。这表示该类型简名可以在导入语句所在的编译单元的任何地方使用.这并不意味着你可以使用该类型所有成员的简名,而只能使用类型自身的简名。例如: java.lang包中的public类都是自动导入的,包括Math和System类.但是,你不能使用它们的成员的简名PI()和gc(),而必须使用Math.PI()和System.gc().你不需要键入的是java.lang.Math.PI()和java.lang.System.gc()。
  4. 程序员有时会导入当前包或java.lang包,这是不需要的,因为当前包的成员本身就在作用域内,而java.lang包是自动导入的。java编译器会忽略这些冗余导入声明(redundant import declarations)。即使像这样import java.util.ArrayList;import java.util.*;多次导入,也可编译通过。编译器会将冗余导入声明忽略.

四、static import静态导入

在Java程序中,是不允许定义独立的函数和常量的。即什么属性或者方法的使用必须依附于什么东西,例如使用类或接口作为挂靠单位才行(在类里可以挂靠各种成员,而接口里则只能挂靠常量)。

如果想要直接在程序里面不写出其他类或接口的成员的挂靠单元,有一种变通的做法 :
将所有的常量都定义到一个接口里面,然后让需要这些常量的类实现这个接口(这样的接口有一个专门的名称,叫(“Constant Interface”)。这个方法可以工作。但是,因为这样一来,就可以从“一个类实现了哪个接口”推断出“这个类需要使用哪些常量”,有“会暴露实现细节”的问题。

于是J2SE 1.5里引入了“Static Import”机制,借助这一机制,可以用略掉所在的类或接口名的方式,来使用静态成员。static import和import其中一个不一致的地方就是static import导入的是静态成员,而import导入的是类或接口类型

如下是一个有静态变量和静态方法的类

package com.assignment.test;
public class staticFieldsClass {
	static int staticNoPublicField = 0;
	public static int staticField = 1;
    public static void staticFunction(){}
}

平时我们使用这些静态成员是用类名.静态成员的形式使用,即staticFieldsClass.staticField或者staticFieldsClass.staticFunction()。

现在用static import的方式:

//**精准导入**
//直接导入具体的静态变量、常量、方法方法,注意导入方法直接写方法名不需要括号。
import static com.assignment.test.StaticFieldsClass.staticField;
import static com.assignment.test.StaticFieldsClass.staticFunction;

//或者使用如下形式:
//**按需导入**不必逐一指出静态成员名称的导入方式
//import static com.assignment.test.StaticFieldsClass.*;

public class StaticTest {
    public static void main(String[] args) {
	    //这里直接写静态成员而不需要通过类名调用
        System.out.println(staticField);
        staticFunction();
    }
}

这里有几个问题需要弄清楚:

  1. Static Import无权改变无法使用本来就不能使用的静态成员的约束,上面例子的StaticTest和staticFieldsClass不是在同一个包下,所以StaticTest只能访问到staticFieldsClass中public的变量。使用了Static Import也同样如此。
  2. 导入的静态成员和本地的静态成员名字相同起了冲突,这种情况下的处理规则,是“本地优先。
  3. 不同的类(接口)可以包括名称相同的静态成员。例如在进行Static Import的时候,出现了“两个导入语句导入同名的静态成员”的情况。在这种时候,J2SE 1.5会这样来加以处理:
  4. 如果两个语句都是精确导入的形式,或者都是按需导入的形式,那么会造成编译错误。
  5. 如果一个语句采用精确导入的形式,一个采用按需导入的形式,那么采用精确导入的形式的一个有效。

大家都这么聪明上面的几个特性我就不写例子了。

static import这么叼那它有什么负面影响吗?

答案是肯定的,去掉静态成员前面的类型名,固然有助于在频繁调用时显得简洁,但是同时也失去了关于“这个东西在哪里定义”的提示信息,理解或维护代码就呵呵了。
但是如果导入的来源很著名(比如java.lang.Math),这个问题就不那么严重了。


五、按需导入机制

使用按需导入声明是否会降低Java代码的执行效率?

**绝对不会! **

1.import的按需导入

import java.util.*;
public class NeedImportTest {
    public static void main(String[] args) {
        ArrayList tList = new ArrayList();
    }
}

编译之后的class文件 :

//import java.util.*被替换成import java.util.ArrayList
//即按需导入编译过程会替换成单类型导入。
import java.util.ArrayList;

public class NeedImportTest {
    public static void main(String[] args) {
        new ArrayList();
    }
}

2.static import的按需导入

import static com.assignment.test.StaticFieldsClass.*;
public class StaticNeedImportTest {
    public static void main(String[] args) {
        System.out.println(staticField);
        staticFunction();
    }
}

上面StaticNeedImportTest 类编译之后 :

//可以看出 :
//1、static import的精准导入以及按需导入编译之后都会变成import的单类型导入
import com.assignment.test.StaticFieldsClass;

public class StaticNeedImportTest {
    public static void main(String[] args) {
    //2、编译之后“打回原形”,使用原来的方法调用静态成员
        System.out.println(StaticFieldsClass.staticField);
        StaticFieldsClass.staticFunction();
    }
}

六、附加

这是否意味着你总是可以使用按需导入声明?
**是,也不是! **

在类似Demo的非正式开发中使用按需导入声明显得很有用。

然而,有这四个理由让你可以放弃这种声明:

  1. 编译速度:在一个很大的项目中,它们会极大的影响编译速度.但在小型项目中使用在编译时间上可以忽略不计。
  2. 命名冲突:解决避免命名冲突问题的答案就是使用全名。而按需导入恰恰就是使用导入声明初衷的否定。
  3. 说明问题:毕竟高级语言的代码是给人看的,按需导入看不出使用到的具体类型。
  4. 无名包问题:如果在编译单元的顶部没有包声明,Java编译器首选会从无名包中搜索一个类型,然后才是按需类型声明。如果有命名冲突就会产生问题。

Sun的工程师一般不使用按需类型导入声明.这你可以在他们的代码中找到:
在java.util.Properties类中的导入声明:

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;

可以看到他们用单类型导入详细的列出了需要的java.io包中的具体类型。

以上就是java中import作用的详细内容,更多关于java中import的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java import static及import原理区别解析

    import static静态导入是JDK1.5中的新特性.一般我们导入一个类都用 import com.....ClassName;而静态导入是这样:import static com.....ClassName.*;这里的多了个static,还有就是类名ClassName后面多了个 .* ,意思是导入这个类里的静态方法.当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了.然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用. 这种方

  • java的package和import机制原理解析

    这篇文章主要介绍了java的package和import机制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在说package.import机制前我们先来了解下java的CLASSPATH. CLASSPATH顾名思义就是class的路径,当我们在系统中运行某个java程序时,它就会告诉系统在这些地方寻找这个class文件 CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar; 这是

  • Java如何基于wsimport调用wcf接口

    wcf接口是由.net提供的webservice接口,一般是使用wsdl文件的样式发布,在wsdl文件中,包含该webservice暴露在外面可供使用的接口. 了解到的调用wfc接口方法有三种: AXIS调用远程webservice SOAP调用远程webservice wsimport生成java代码,调用接口 在尝试方法1.2多次失败后,果断放弃,选择了简单易上手的方法3.通过jdk6.0以上版本自带的wsimport工具,即可根据wsdl文件生成相应的类文件.将这些生成的文件放在相应项目,

  • Java里的static import使用小结

    换了工作要把Java重新捡起来了,这个在大学里用过的语言,虽然不复杂,还是有一些奇怪的地方的.比如static import. Static import是JDK 1.5中引进的特性,不过读大学那会还真没注意到.它的作用是把静态(static)的方法或者常量import进来.比如: import static java.lang.Math.*; public class HelloWorld { public static void main(String[] args) { System.ou

  • JAVA WSIMPORT生成WEBSERVICE客户端401认证过程图解

    概述 wsimport是jdk自带的命令,可以根据wsdl文档生成客户端中间代码,基于生成的代码编写客户端,可以省很多麻烦. 先看两张截图: 使用浏览器打开webservice出现的界面: 使用wsimport生成webservice客户端出现401错误: 需用到的命令参数如下: 1. -d <directory> 在指定的目录生成class文件 2. -p <pkg> 指定生成文件的包结构 3. -Xauthfile <filepath> 在格式文件进行授权信息 4.

  • Java import导入及访问控制权限修饰符原理解析

    这篇文章主要介绍了Java import导入及访问控制权限修饰符过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.import 1.import语句用来完成导入其他类,同一个包下的类不需要再导入 不在同一个包下需要手动导入. 2.import语法格式 import 类名: import 包名.*; //import语句需要编写到package语句之下,class语句之上. 3.java.lang.*;不需要手动引入,​系统自动引入.

  • java入门概念个人理解之package与import浅析

    由于近来学习java,遇到了一些在c++上没有的概念,将它记录下,以自己复习使用,如有不理解妥之处,望大家批评指导.资料均由网上经过自己整合理解而来,如有侵权请通知我将起删除即可. 我就以package与import开始吧. package的作用其实就是c++的namespace的作用,防止名字相同的类产生冲突,只是实现的机制不一样,java编译器在编译时,直接根据package 指定的信息直接将生成的class文件生成到对应目录下.如package aaa.bbb.ccc 编译器就将该.jav

  • 详解Java类库的概念以及import的使用方法

    Java类库及其组织结构(Java API) Java 官方为开发者提供了很多功能强大的类,这些类被分别放在各个包中,随JDK一起发布,称为Java类库或Java API. API(Application Programming Interface, 应用程序编程接口)是一个通用概念. 例如我编写了一个类,可以获取计算机的各种硬件信息,它很强大很稳定,如果你的项目也需要这样一个功能,那么你就无需再自己编写代码,将我的类拿来直接用就可以.但是,我的类代码很复杂,让你读完这些代码不太现实,而且我也不

  • 详解java中import的作用

    一.package C/C++ 的 #include会把所包含的内容在编译时添加到程序文件中,而java的import则不同. 这里我们先了解一下Java 的 package 到底有何用处. package名称就像是我们的姓,而class名称就像是我们的名字 .package和package的附属关系用"."来连接,这就像是复姓.比如说 java.lang.String就是复姓 java.lang,名字為 String 的类别:java.io.InputStream 则是复姓 java

  • 详解JAVA中static的作用

    1.深度总结 引用一位网友的话,说的非常好,如果别人问你static的作用:如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的:如果是说 可以构成 静态代码块,那别人认为你还可以: 如果你说可以构成 静态内部类, 那别人认为你不错:如果你说了静态导包,那别人认为你很OK: 那我们就先在这几方面一一对static进行总结:然后说一些模糊的地方,以及一些面试中容易问道的地方: 1)static方法 static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方

  • 详解Java中@Override的作用

    详解Java中@Override的作用 @Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1.可以当注释用,方便阅读: 2.编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错.例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法. 举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性. @Overr

  • 详解Java中hashCode的作用

    详解Java中hashCode的作用 以下是关于HashCode的官方文档定义: hashcode方法返回该对象的哈希码值.支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表. hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改.从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致. 如果根据

  • 详解java中static关键词的作用

    在java中,static是一个修饰符,用于修饰类的成员方法.类的成员变量,另外可以编写static代码块来优化程序性能:被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问. static关键词的作用 1.静态成员变量的语法特定 2.静态函数的语法特定 3.静态代码块的语法特定 定义静态成员变量 Person.java class Person{ static int a; } 按照以前可以这么调用 public class Test1{

  • 详解Java中list,set,map的遍历与增强for循环

    详解Java中list,set,map的遍历与增强for循环 Java集合类可分为三大块,分别是从Collection接口延伸出的List.Set和以键值对形式作存储的Map类型集合. 关于增强for循环,需要注意的是,使用增强for循环无法访问数组下标值,对于集合的遍历其内部采用的也是Iterator的相关方法.如果只做简单遍历读取,增强for循环确实减轻不少的代码量. 集合概念: 1.作用:用于存放对象 2.相当于一个容器,里面包含着一组对象,其中的每个对象作为集合的一个元素出现 3.jav

  • 详解java中的static关键字

    Java中的static关键字可以用于修饰变量.方法.代码块和类,还可以与import关键字联合使用,使用的方式不同赋予了static关键字不同的作用,且在开发中使用广泛,这里做一下深入了解. 静态资源(静态变量与静态方法) 被static关键字修饰的变量和方法统一属于类的静态资源,是类实例之间共享的.被static关键字修饰的变量.方法属于类变量.类方法,可以通过[类名.变量名].[类名.方法名]直接引用,而不需要派生一个类实例出来. 静态资源分类存放的好处 JDK把不同的静态资源放在了不同的

  • 详解Java中native方法的使用

    今天在网上学习时碰到有关于 native修饰符所修饰的方法,上网查了查,觉得很有意思记录一下 1.native简介 简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C.这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数. native是与C++联合开发的时候用的!使用nat

  • 详解Java中的ReentrantLock锁

    ReentrantLock锁 ReentrantLock是Java中常用的锁,属于乐观锁类型,多线程并发情况下.能保证共享数据安全性,线程间有序性 ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁, 下面说一下锁的基本使用和底层基本实现原理,lock和unlock底层 lock的时候可能被其他线程获得所,那么此线程会阻塞自己,关键原理底层用到Unsafe类的API: CAS和park 使用 java.util.concurrent.locks.R

  • 详解Java中的反射机制和动态代理

    一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制.通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以,这是一种动态获取类的信息以及动态调用对象方法的能力. 想要使用反射机制,就必须要先获取到该类

随机推荐