import 在java 中的⽤法
import 与package 机制相关,这⾥先从package ⼊⼿,再讲述import 以及static 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 的名称⾮常的长,在编程时,要使⽤⼀个类要将多个包名.类名完全写出,会让代码变得冗长,减低了简洁度。例如显得⾮常⿇烦,于是Sun 公司就引⼊了import 。
import
import 就是在java ⽂件开头的地⽅,先说明会⽤到那些类别。
接着我们就能在代码中只⽤类名指定某个类,也就是只称呼名字,不称呼他的姓。
⾸先,在程序开头写:
于是我们就可以在程序中这样写到:
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);
1
2
3import java.lang.System;import java.io.InputStream;import java.io.InputStreamReader;import java.io.BufferedReader;
1
2
3
4InputStream = System.in ;InputStreamReader isr = new InputStreamReader(is );BufferedReader br = new BufferedReader(isr);
1
2
3
⼀个java ⽂件就像⼀个⼤房间,我们在门⼝写着在房间⾥⾯的class 的姓和名字,所以在房间⾥⾯提到
某个class 就直接⽤他的名字就可以。例如:
System 就是指 java.lang.System ,⽽ InputStream 就是指 java.io.InputStream 。
但是如果⼀个java ⽂件⾥⾯有多个同个“姓”,即包名相同的类(例如上⾯的InputStream ,InputStreamReader ,BufferedReader 都是java.io 中的类),我们⼀⼀写出显得⽐较繁杂,所以Sun 就让我们可以使⽤表⽰⽂件⾥⾯说到的类不是java.lang 包的就是java.io 包的。编译器会帮我们选择与类名对应的包。
那我们可不可以再懒⼀点直接写成下⾯声明呢?历史告诉我们,这样是不⾏的。因為那些类别是姓 java.io ⽽不是姓 java 。就像姓『诸葛』的⼈应该不会喜欢你称他為『诸』 先⽣吧。这样写的话只会将java 包下的类声明,⽽不不会声明⼦包的任何类。
这⾥注意,java.lang 包⾥⾯的类实在是太常太常太常⽤到了,⼏乎没有类不⽤它的, 所以不管你有没有写 import java.lang ,编译器都会⾃动帮你补上,也就是说编译器只要看到没有姓的类别,它就会⾃动去lang 包⾥⾯查。所以我们就不⽤特别去 import java.lang 了。
⼀开始说 import 跟 #include 不同,是因为import 的功能到此為⽌,它不像#include ⼀样,会将其他java ⽂件的内容载⼊进来。import 只是让编译器编译这个java ⽂件时把没有姓的类别加上姓,并不会
把别的⽂件程序写进来。你开⼼的话可以不使⽤import ,只要在⽤到类别的时候,⽤它的全部姓名来称呼它就⾏了(就像例⼦⼀开始那样),这样跟使⽤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()和().你不需要键⼊的是java.lang.Math.PI()和java.()。
import java.lang.*;import java.io.*;
1
2import java.*;
1
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 导⼊的是类或接⼝类型。
如下是⼀个有静态变量和静态⽅法的类平时我们使⽤这些静态成员是⽤类名.静态成员的形式使⽤,即staticFieldsClass.staticField 或者staticFieldsClass.staticFunction()。现在⽤static import 的⽅式:这⾥有⼏个问题需要弄清楚:
package st;public class staticFieldsClass { static int staticNoPublicField = 0; public static int staticField = 1; public static void staticFunction (){}}
1
2
3
4
5
6
7//**精准导⼊**//直接导⼊具体的静态变量、常量、⽅法⽅法,注意导⼊⽅法直接写⽅法名不需要括号。
import static st.StaticFieldsClass.staticField;import static st.StaticFieldsClass.staticFunction;//或者使⽤如下形式://**按需导⼊**不必逐⼀指出静态成员名称的导⼊⽅式//import static st.StaticFieldsClass.*;public class StaticTest { public static void main (String[] args) { //这⾥直接写静态成员⽽不需要通过类名调⽤ System.out .println(staticField); staticFunction(); }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. Static Import ⽆权改变⽆法使⽤本来就不能使⽤的静态成员的约束,上⾯例⼦的StaticTest 和staticFieldsClass 不是在同⼀个包下,所以StaticTest 只能访问到staticFieldsClass 中public 的变量。使⽤了Static Import 也同样如此。
2. 导⼊的静态成员和本地的静态成员名字相同起了冲突,这种情况下的处理规则,是“本地优先。
3. 不同的类(接⼝)可以包括名称相同的静态成员。例如在进⾏Static Import 的时候,出现了“两个导⼊语句导⼊同名的静态成员”的情况。在这种时候,J2SE 1.5会这样来加以处理:
1. 如果两个语句都是精确导⼊的形式,或者都是按需导⼊的形式,那么会造成编译错误。
2. 如果⼀个语句采⽤精确导⼊的形式,⼀个采⽤按需导⼊的形式,那么采⽤精确导⼊的形式的⼀个有效。
⼤家都这么聪明上⾯的⼏个特性我就不写例⼦了。
static import 这么叼那它有什么负⾯影响吗?
答案是肯定的,去掉静态成员前⾯的类型名,固然有助于在频繁调⽤时显得简洁,但是同时也失去了关于“这个东西在哪⾥定
义”的提⽰信息,理解或维护代码就呵呵了。
但是如果导⼊的来源很著名(⽐如java.lang.Math ),这个问题就不那么严重了。
按需导⼊机制
使⽤按需导⼊声明是否会降低Java 代码的执⾏效率?
绝对不会!
⼀、import 的按需导⼊编译之后的class ⽂件 :⼆、static import 的按需导⼊
import java.util.*;public class NeedImportTest { public static void main (String[] args) { ArrayList tList = new ArrayList(); }}
1
2
3
4
5
6
7//import java.util.*被替换成import java.util.ArrayList //即按需导⼊编译过程会替换成单类型导⼊。import java.util.ArrayList;public class NeedImportTest { public static void main (String[] args) { new ArrayList(); }}
1
2
3
4
5
6
7
8
9
上⾯StaticNeedImportTest 类编译之后 :
附加
这是否意味着你总是可以使⽤按需导⼊声明?
是,也不是!
在类似Demo 的⾮正式开发中使⽤按需导⼊声明显得很有⽤。
然⽽,有这四个理由让你可以放弃这种声明:
1. 编译速度:在⼀个很⼤的项⽬中,它们会极⼤的影响编译速度.但在⼩型项⽬中使⽤在编译时间上可以忽略不计。
2. 命名冲突:解决避免命名冲突问题的答案就是使⽤全名。⽽按需导⼊恰恰就是使⽤导⼊声明初衷的否定。
3. 说明问题:毕竟⾼级语⾔的代码是给⼈看的,按需导⼊看不出使⽤到的具体类型。
4. ⽆名包问题:如果在编译单元的顶部没有包声明,Java 编译器⾸选会从⽆名包中搜索⼀个类型,然
后才是按需类型声明。如果有命名冲突就会产⽣问题。
Sun 的⼯程师⼀般不使⽤按需类型导⼊声明.这你可以在他们的代码中到:
在java.util.Properties 类中的导⼊声明:
import static st.StaticFieldsClass.*;public class StaticNeedImportTest { public static void main (String[] args) { System.out .println(staticField); staticFunction(); }}
1
2
3
4
5
6
7//可以看出 : //1、static import 的精准导⼊以及按需导⼊编译之后都会变成import 的单类型导⼊import st.StaticFieldsClass;public class StaticNeedImportTest { public static void main (String[] args) { //2、编译之后“打回原形”,使⽤原来的⽅法调⽤静态成员 System.out .println(StaticFieldsClass.staticField); StaticFieldsClass.staticFunction(); }}
1
2
3
4
5
6
7
8
9
10
11import 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;1
2
3
4
5
6
7
8
9
10
11
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论