??xml version="1.0" encoding="utf-8" standalone="yes"?>
Starting with JDK 1.1, Java provided the ability to create nested classes. A nested class is defined inside another class. There are two types of nested classes: static nested classes and inner classes.
A static nested class is declared inside another class with the static keyword or within a static context of that class. A static class has no access to instance-specific data.
An inner class is a nonstatic class declared inside another class. It has access to all of its enclosing class's instance data, including private fields and methods. Inner classes may access static data but may not declare static members unless those members are compile time constants.
Deciding which type of nested class to use depends on the data type your nested class needs to access. If you need access to instance data, you'll need an inner class. If you don't need access to instance data, a static nested class will suffice.
The most common use of inner classes is as event handlers for GUI-based applications. These classes are usually declared anonymously and as needed for each component that requires an event handler. The advantage of using an inner class for event handling is that you can avoid large If/else statements to decide which component is being handled. Each component gets its own event handler, so each event handler knows implicitly the component for which it's working.
The snippet below creates an anonymous inner class to handle the events created by an application's OK button.
Button btn = new Button("Ok");
The advantage of a static nested class is that it doesn't need an instance of the containing class to work. This can help you reduce the number of objects your application creates at runtime.
The semantics for creating instances of nested classes can be confusing. Below is a simple class that defines a static nested class and an inner class. Pay special attention to the main method, where an instance of each instance class is created.
// creating an instance of the enclosing class
Nested classes can be confusing, but once you understand their purpose and get used to the semantics, there isn't a lot to them. If you'd like to learn more about the details of nested classes, check out the Java Language Specification.
Explore Java's static nested classes and inner classes
by
David Petersheim
|
More from David Petersheim
| Published: 8/12/05
btn.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent ae) {
okClicked();
}
}
);
NestedClassTip nt = new NestedClassTip();
// creating an instance of the inner class requires
// a reference to an instance of the enclosing class
NestedClassTip.NestedOne nco = nt.new NestedOne();
// creating an instance of the static nested class
// does not require an instance of the enclosing class
NestedClassTip.NestedTwo nct = new NestedClassTip.NestedTwo();
public class NestedClassTip {
private String name = "instance name";
private static String staticName = "static name";
public static void main(String args[]) {
NestedClassTip nt = new NestedClassTip();
NestedClassTip.NestedOne nco = nt.new NestedOne();
NestedClassTip.NestedTwo nct = new NestedClassTip.NestedTwo();
}
class NestedOne {
NestedOne() {
System.out.println(name);
System.out.println(staticName);
}
}
static class NestedTwo {
NestedTwo() {
System.out.println(staticName);
}
}
}
]]>
]]>
The following tips hints how to make Hibernate startup faster.
If you are running some few JUnit tests for a 400++ classes project you probably don't hit every class in those tests and thus do not need to add all those hbm.xml's to the Configuration. Go look at Hibernate's test suite on how you could let your TestCase decide what classes should be defined in the mapping.
When building the configuration 40-60% of the time is used by the XML parsers and Dom4j to read up the XML document. Significant performance increases can be done by serializing the Document object's to disc once, and afterwards just add them to the configuration by deserializing them first.
In the current cvs we have an experimental Configuration.addCachableFile() method that can be used as inspiration for previous Hibernate versions.
public Configuration addCachableFile(String xmlFile) throws MappingException { try { File file = new File(xmlFile); File lazyfile = new File(xmlFile + ".bin"); org.dom4j.Document doc = null; List errors = new ArrayList(); if(file.exists() && lazyfile.exists() && file.lastModified()<lazyfile.lastModified()) { log.info("Mapping lazy file: " + lazyfile.getPath()); ObjectInputStream oip = null; oip = new ObjectInputStream(new FileInputStream(lazyfile)); doc = (org.dom4j.Document) oip.readObject(); oip.close(); } else { doc = xmlHelper.createSAXReader(xmlFile, errors, entityResolver).read( file ); log.info("Writing lazy file to " + lazyfile); ObjectOutputStream oup = new ObjectOutputStream(new FileOutputStream(lazyfile)); oup.writeObject(doc); oup.flush(); oup.close(); } if ( errors.size()!=0 ) throw new MappingException( "invalid mapping", (Throwable) errors.get(0) ); add(doc); return this; } catch (Exception e) { log.error("Could not configure datastore from file: " + xmlFile, e); throw new MappingException(e); } }
Put the following line in hibernate.properties:
hibernate.cglib.use_reflection_optimizer=falseIt will make Hibernate start faster since it does not try to build cglib-enhanced objects to access getter/setters.
Note: It will have in impact on overall runtime performance since Hibernate will be forced to use standard JDK reflection for access. So it is most useful during development. (You will also get better error messages in some situations when the optimizer is disabled ;)
NEW COMMENT |
Serializing the Configuration object
|
04 May 2004, 12:37 | luish |
Another approach would be to serialize the whole Configuration object. What do you think about this? I have submitted a patch to the Jira to make the Configuration Serializable (see bugs 492 and 147). |
||
addLazyFile() not there.
|
06 Jul 2004, 11:50 | gstamp |
I can't fine addLazyFile() in CVS. Is it still supposed to be there? |
||
Hibernate3 feature
|
31 Aug 2004, 11:13 | gavin |
Try the Hibernate3 module (or just the alpha release) |
||
Information update?
|
30 Mar 2005, 07:54 | gruberc |
The information on this page does not seem to be correct any more. With Hibernate 3.0rc1, there is no Configuration.addLazyFile() any more, but addCacheableFile(). How should it be used? |
||
lazy
|
06 Mar 2006, 05:09 | steckemetz |
If you have terrible problems with startup time and do NOT need certain features like: * proxy objects * lazy loading or if you are using the stateless session, then you can disable lazyness on class level like: <class name="myClass" table="myTable" lazy="false"> The default is true and forces byte code generation of some proxy class which takes a lot of time. Perhaps some hibernate guru can tell us, which other features will be disabled by this. |
||
I solve it.
|
02 Aug 2006, 00:12 | cm4ever |
The Hibernate Configuration module implement is very bad. I write a module to realize the dynamic loading mapping files. But other function I can't resolve... Hibernate Dynamic Module This project is only a module of Hibernate http://www.hibernate.org Read mapping file until insert/update/delete/select the persistent class in Hibernate. http://sourceforge.net/projects/hbn-dyn-mod/ |
try {
FileInputStream fis = new FileInputStream("serial");
ObjectInputStream ois = new ObjectInputStream(fis);
configuration = (Configuration) ois.readObject();
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
catch (ClassNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
if(configuration!=null)
{
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
callBack.doing(session);
transaction.commit();
}
}
when will Configuration serialize and why it's some field seted transient?the example will be error because some field transient is null after serialize.
importjava.text.CollationKey;
import java.text.Collator;
import java.util.Comparator;
/**
*@author www.inspiresky.com
*
*/
publicclass CollatorComparator implements Comparator {
Collator collator = Collator.getInstance();
publicint compare(Object element1, Object element2) {
CollationKey key1 = collator.getCollationKey(element1.toString());
CollationKey key2 = collator.getCollationKey(element2.toString());
return key1.compareTo(key2);
}
}
import java.util.Date;
public class DateExample1 {
public static void main(StringQ] args) { //自己替换Q]
// Get the system date/time
Date date = new Date();
System.out.println(date.getTime());
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateExample2 {
public static void main(StringQ] args) { //自己替换Q]
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
Date date = new Date();
System.out.println(bartDateFormat.format(date));
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateExample3 {
public static void main(StringQ]args) { //自己替换Q]
// Create a date formatter that can parse dates of
// the form MM-dd-yyyy.
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("MM-dd-yyyy");
// Create a string containing a text date to be parsed.
String dateStringToParse = "9-29-2001";
try {
// Parse the text version of the date.
// We have to perform the parse method in a
// try-catch construct in case dateStringToParse
// does not contain a date in the format we are expecting.
Date date = bartDateFormat.parse(dateStringToParse);
// Now send the parsed date as a long value
// to the system output.
System.out.println(date.getTime());
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
import java.text.DateFormat;
import java.util.Date;
public class DateExample4 {
public static void main(StringQ] args) { //自己替换Q]
Date date = new Date();
DateFormat shortDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.SHORT,
DateFormat.SHORT);
DateFormat mediumDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.MEDIUM,
DateFormat.MEDIUM);
DateFormat longDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.LONG);
DateFormat fullDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL);
System.out.println(shortDateFormat.format(date));
System.out.println(mediumDateFormat.format(date));
System.out.println(longDateFormat.format(date));
System.out.println(fullDateFormat.format(date));
}
}
The DATE data type stores date and time information. For each DATE value, Oracle stores the following information: year, month, day, hour, minute, and second.
The date value can be specified as an ANSI date literal, an Oracle date literal or can be converted from a character or numeric value with the TO_DATE function. The ANSI date literal contains no time portion, and must be specified in the format 'YYYY-MM-DD'. The default date format for an Oracle date literal can be changed by the initialization parameter NLS_DATE_FORMAT.
Date data can range from January 1, 4712 BC to December 31, 9999.
If a date value is specified without a time component, then the default time is 12:00:00 AM. If a date value is specified without a date, then the default date is the first day of the current month.
---------------------------------------------------------------------------------------------------------------------------------------------------
TIMESTAMP[(fractional_seconds_precision)]
The TIMESTAMP data type is an extension of the DATE data type. For each TIMESTAMP value, Oracle stores the following information: year, month, day, hour, minute, second and fraction of second.
fractional_seconds_precision optionally specifies the number of digits in the fractional part of second and can be a number in the range 0 to 9. The default is 6.
The TIMESTAMP data type is available in Oracle 9i Release 1 (9.0.1) or later.
Field fields[] = c.getDeclaredFields( );
where c is initialized using
Class c = Class.forName(className);
and print the fields array, you get all the elements declared in the class.
However, suppose you want to restrict the output to all fields other than those declared as private. In this case, you would use the following code, where the Modifier class is a part of the java.lang.reflect package:
if(!Modifier.isPrivate(fields[i].getModifiers( )){
System.out.println(fields[i]+"\n");
}
Using Modifier.isPrivate() ensures that the private variables are not printed.
The same can be used for methods as well.
author: MS SridharThreadLocalq是一个线E的本地实现版本Q它q不是一个ThreadQ而是thread local variableQ线E局部变量)。也许把它命名ؓThreadLocalVar更加合适。线E局部变量(ThreadLocalQ其实的功用非常单,是为每一个用该变量的线E都提供一个变量值的副本Q是每一个线E都可以独立地改变自q副本Q而不会和其它U程的副本冲H。从U程的角度看Q就好像每一个线E都完全拥有该变量。线E局部变量ƈ不是Java的新发明Q在其它的一些语a~译器实玎ͼ如IBM XL FORTRANQ中Q它在语a的层ơ提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线E局部变量的代码相对比较W拙Q这也许是线E局部变量没有在Java中得到很好的普及的一个原因吧?/p>
二、ThreadLocal的设?/strong>
首先看看ThreadLocal的接口:
Object get() ;
// q回当前U程的线E局部变量副?protected Object initialValue(); // q回该线E局部变量的当前U程的初始?/p>
void set(Object value);
// 讄当前U程的线E局部变量副本的?/p>
ThreadLocal?个方法,其中值得注意的是initialValue()Q该Ҏ是一个protected的方法,昄是ؓ了子c重写而特意实现的。该Ҏq回当前U程在该U程局部变量的初始|q个Ҏ是一个gq调用方法,在一个线E第1ơ调用get()或者set(Object)时才执行Qƈ且仅执行1ơ。ThreadLocal中的实实现直接q回一个nullQ?/p>
protected Object initialValue() { return null; }
ThreadLocal是如何做Cؓ每一个线E维护变量的副本的呢Q其实实现的思\很简单,在ThreadLocalcM有一个MapQ用于存储每一个线E的变量的副本。比如下面的CZ实现Q?/p>
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
当然Q这q不是一个工业强度的实现Q但JDK中的ThreadLocal的实现M思\也类g此?/p>
三、ThreadLocal的?/strong>
如果希望U程局部变量初始化其它|那么需要自己实现ThreadLocal的子cdƈ重写该方法,通常使用一个内部匿名类对ThreadLocalq行子类化,比如下面的例子,SerialNumcMؓ每一个类分配一个序P
public class SerialNum
{
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal()
{
protected synchronized Object initialValue()
{
return new Integer(nextSerialNum++);
}
};
public static int get()
{
return ((Integer) (serialNum.get())).intValue();
}
}
SerialNumcȝ使用非常地单,因ؓget()Ҏ是static的,所以在需要获取当前线E的序号Ӟ单地调用Q?/p>
int serial = SerialNum.get();
卛_?/p>
在线E是zd的ƈ且ThreadLocal对象是可讉K的时Q该U程持有一个到该线E局部变量副本的隐含引用Q当该线E运行结束后Q该U程拥有的所以线E局部变量的副本都将失效Qƈ{待垃圾攉器收集?br />
四、ThreadLocal与其它同步机制的比较
ThreadLocal和其它同步机制相比有什么优势呢QThreadLocal和其它所有的同步机制都是Z解决多线E中的对同一变量的访问冲H,在普通的同步机制中,是通过对象加锁来实现多个线E对同一变量的安全访问的。这时该变量是多个线E共享的Q用这U同步机刉要很l致地分析在什么时候对变量q行dQ什么时候需要锁定某个对象,什么时候释放该对象的锁{等很多。所有这些都是因为多个线E共享了资源造成的。ThreadLocal׃另一个角度来解决多线E的q发讉KQThreadLocal会ؓ每一个线E维护一个和该线E绑定的变量的副本,从而隔M多个U程的数据,每一个线E都拥有自己的变量副本,从而也没有必要对该变量进行同步了。ThreadLocal提供了线E安全的׃n对象Q在~写多线E代码时Q可以把不安全的整个变量装qThreadLocalQ或者把该对象的特定于线E的状态封装进ThreadLocal?/p>
׃ThreadLocal中可以持有Q何类型的对象Q所以用ThreadLocal get当前U程的值是需要进行强制类型{换。但随着新的Java版本Q?.5Q将模版的引入,新的支持模版参数的ThreadLocalcd从中受益。也可以减少强制cd转换Qƈ一些错误检查提前到了编译期Q将一定程度地化ThreadLocal的用?/p>
五、ȝ
当然ThreadLocalq不能替代同步机Ӟ两者面向的问题领域不同。同步机制是Z同步多个U程对相同资源的q发讉KQ是Z多个U程之间q行通信的有效方式;而ThreadLocal是隔d个线E的数据׃nQ从Ҏ上就不在多个U程之间׃n资源Q变量)Q这样当然不需要对多个U程q行同步了。所以,如果你需要进行多个线E之间进行通信Q则使用同步机制Q如果需要隔d个线E之间的׃n冲突Q可以用ThreadLocalQ这极大地化你的程序,使程序更加易诅R简z?/p>
class BadArithmetic {
static byte addOneAndOne() {
byte a = 1;
byte b = 1;
byte c = (a + b);
return c;
}
}
当遇CqC码时Qjavac会给出如下提C:
type.java:6: possible loss of precision
found : int
required: byte
byte c = (a + b);
^
1 error
Z对这U情况进行补救,必须把a + b所获得的intcdl果昑ּ转换为bytecd。代码如下:
class GoodArithmetic {
static byte addOneAndOne() {
byte a = 1;
byte b = 1;
byte c = (byte)(a + b);
return c;
}
}
该操作能够通过javac的编译,q生GoodArithmetic.class文g?BR>
char ccc=98;
System.err.println( ccc);//out put is b
true
if the named file does not exist and was successfully created; false
if the named file already exists
没有泛型的日?/STRONG>
所有的javac都源自java.lang.Object,q意味着所有的JAVA对象能{换成Object。因此,在之前的JDK的版本中Q很多Collections framework的函数接受一个Object参数。所以,collections是一个能持有M对象的多用途工P但带来了不良的后果?BR> 举个单的例子Q在JDK 5.0的之前版本中Q类List的函数add接受一个Object参数Q?BR>
public boolean add(java.lang.Object element)
所以你能传递Q何类型给add。这是故意这么设计的。否则,它只能传递某U特定的对象Q这样就会出现各UListcdQ如QStringList, EmployeeList, AddressList{?BR> add通过Object传递能带来好处,现在我们考虑get函数(q回List中的一个元?.如下是JDK 5之前版本的定义:
public java.lang.Object get(int index) throws IndexOutOfBoundsException
getq回一个Object.不幸的事情从此开始了.假如你储存了两个String对象在一个List?
List stringList1 = new ArrayList();
stringList1.add("Java 5");
stringList1.add("with generics");
当你想从stringList1取得一个元素时,你得C一个Object.Z操作原来的类型元?你不得不把它转换String?BR>
String s1 = (String) stringList1.get(0);
但是,假如你曾l把一个non-String对象加入stringList1?上面的代码会抛出一个ClassCastException.
有了泛型,你能创徏一个单一用途的List实例.比如,你能创徏一个只接受String对象的List实例,另外一个实例只能接受Employee对象.q同样适用于Collections framework中的其他cd.
泛型入门
像一个函数能接受参数一?一个泛型类也能接受参数.q就是一个泛型类l常被称Z个parameterized type的原?但是不像函数?)传递参?泛型cL?lt;>传递参数的.声明一个泛型类和声明一个普通类没有什么区?只不q你把泛型的变量攑֜<>?
比如,在JDK 5?你可以这样声明一个java.util.List : List<E> myList;E UCؓtype variable.意味着一个变量将被一个类型替?替代type variable的值将被当作参数或q回cd.对于List接口来说,当一个实例被创徏以后,E 被当作一个add或别的函数的参数.E 也会使get或别的参数的q回?下面是add和get的定?
boolean add<E o>
E get(int index)
NOTE:一个泛型在声明或例C时允许你传递特定的type variable: E.除此之外,如果E是个c,你可以传递子c;如果E是个接口Q你可以传递实现接口的c;
-----------------------------译者添?-------------------
List<Number> numberList= new ArrayList<Number>();
numberList.add(2.0);
numberList.add(2);
-----------------------------译者添?-------------------
如果你传递一个Stringl一个ListQ比如:
List<String> myList;
那么mylist的add函数接受一个String作ؓ他的参数Q而get函数返回一个String.因ؓq回了一个特定的cdQ所以不用类型{化了?/P>
NOTEQ根据惯例,我们使用一个唯一的大写字目表CZ个type variable。ؓ了创Z个泛型类Q你需在声明时传递同L参数列表。比如,你要惛_Z个ArrayList来操作String Q你必须把String攑֜<>
中。如Q?BR>
List<String> myList = new ArrayList<String>();
再比如,java.util.Map 是这么定义的Q?BR>
public interface Map<K,V>
K用来声明map密钥(KEY)的类型而V用来表示?VALUE)的类型。put和values是这么定义的Q?BR>
V put(K key, V value)
Collection<V> values()
NOTE:一个泛型类不准直接的或间接的是java.lang.Throwable的子cR因为异常是在run time抛出?所以它不可能预a什么类型的异常在compile time抛出.
列表1的例子将比较List在JDK 1.4 和JDK1.5的不?BR>
package com.brainysoftware.jdk5.app16;
import java.util.List;
import java.util.ArrayList;
public class GenericListTest {
public static void main(String[] args) {
// in JDK 1.4
List stringList1 = new ArrayList();
stringList1.add("Java 1.0 - 5.0");
stringList1.add("without generics");
// cast to java.lang.String
String s1 = (String) stringList1.get(0);
System.out.println(s1.toUpperCase());
// now with generics in JDK 5
List<String> stringList2 = new ArrayList<String>();
stringList2.add("Java 5.0");
stringList2.add("with generics");
// no need for type casting
String s2 = stringList2.get(0);
System.out.println(s2.toUpperCase());
}
}
在列?中,stringList2是个泛型cR声明List<String>告诉~译器List的实例能接受一个String对象。当Ӟ在另外的情况中,你能新徏能接受各U对象的List实例。注意,当从List实例中返回成员元素时Q不需要对象{化,因ؓ他返回的了你惌的类型,也就是String.
NOTE:泛型的类型检?type checking)是在compile time完成?
最让h感兴的事情是,一个泛型类型是个类型ƈ且能被当作一个type variable。比如,你想你的List储存lists of Strings,你能通过把List<String>作ؓ他的type variable来声明List。比如:
List<List<String>> myListOfListsOfStrings;
要从myList中的W一个List重新取得StringQ你可以q么用:
String s = myListOfListsOfStrings.get(0).get(0);
下一个列表中的ListOfListsTestcȝ范了一个ListQ命名ؓlistOfListsQ接受一个String List作ؓ参数?BR>package com.brainysoftware.jdk5.app16;
import java.util.ArrayList;
import java.util.List;
public class ListOfListsTest {
public static void main(String[] args) {
List<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("Hello again");
List<List<String>> listOfLists = new ArrayList<List<String>>();
listOfLists.add(listOfStrings);
String s = listOfLists.get(0).get(0);
System.out.println(s); // prints "Hello again"
}
}
另外Q一个泛型类型接受一个或多个type variable。比如,java.util.Map有两个type variables。第一个定义了密钥QkeyQ的cdQ第二个定义了|value)的类型。下面的例子讲教我们如何使用个一个泛型Map.
package com.brainysoftware.jdk5.app16;
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
String value1 = map.get("key1");
}
}
在这个例子中Q重新得C个key1代表的String|我们不需要Q何类型{换?/P>
没有参数的情况下使用泛型
既然在J2SE 5.0中收集类型已l泛型化Q那么,原来的用这些类型的代码如何呢Q很q运Q他们在JAVA 5中将l箋工作Q因Z能用没有参数的泛型cd。比如,你能l箋像原来一样用List接口Q正如下面的例子一栗?BR>
List stringList1 = new ArrayList();
stringList1.add("Java 1.0 - 5.0");
stringList1.add("without generics");
String s1 = (String) stringList1.get(0);
一个没有Q何参数的泛型cd被称为raw type。它意味着q些为JDK1.4或更早的版本而写的代码将l箋在java 5中工作?/P>
管如此Q一个需要注意的事情是,JDKQ编译器希望你用带参数的泛型类型。否则,~译器将提示警告Q因Z认ؓ你可能忘了定义type variables。比如,~译上面的代码的时候你会看C面这些警告,因ؓW一个List被认为是 raw type?/P>
Note: com/brainysoftware/jdk5/app16/GenericListTest.java
uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
当你使用raw typeӞ如果你不想看到这些警告,你有几个选择来达到目的:
1.~译时带上参?source 1.4
2.使用@SupressWarnings("unchecked")注释
3.更新你的代码Q用List<Object>. List<Object>的实例能接受Mcd的对象,像是一个raw type List。然而,~译器不会发脾气?/P>
使用 Q?通配W?/STRONG>
前面提过Q如果你声明了一个List<aType>, 那么q个List对aType起作用,所以你能储存下面这些类型的对象Q?BR>1.一个aType的实?BR>2.它的子类的实?如果aType是个c?
3.实现aType接口的类实例(如果aType是个接口)
但是Q请注意Q一个泛型本w是个JAVAcdQ就像java.lang.String或java.io.File一栗传递不同的type variablel泛型可以创Z同的JAVAcd。比如,下面例子中list1和list2引用了不同的cd对象?BR>
List<Object> list1 = new ArrayList<Object>();
List<String> list2 = new ArrayList<String>();
list1指向了一个type variables为java.lang.Objects 的List而list2指向了一个type variables为String 的List。所以传递一个List<String>l一个参CؓList<Object>的函数将Dcompile time错误。下面列表可以说明:
package com.brainysoftware.jdk5.app16;
import java.util.ArrayList;
import java.util.List;
public class AllowedTypeTest {
public static void doIt(List<Object> l) {
}
public static void main(String[] args) {
List<String> myList = new ArrayList<String>();
// q里生一个错?BR> doIt(myList);
}
}
上面的代码无法编译,因ؓ你试图传递一个错误的cdl函数doIt。doIt的参数是List<Object>二你传递的参数是List<String>?/P>
可以使用 Q?通配W解册个难题。List<?> 意味着一个对M对象起作用的List。所以,doIt可以改ؓQ?BR>
public static void doIt(List<?> l) {}
在某些情况下你会考虑使用 ? 通配W。比如,你有一个printList函数Q这个函数打C个List的所有成员,你想让这个函数对Mcd的List起作用时。否则,你只能篏ȝzȝ写很多printList的重载函数。下面的列表引用了?? 通配W的printList函数?/P>
package com.brainysoftware.jdk5.app16;
import java.util.ArrayList;
import java.util.List;
public class WildCardTest {
public static void printList(List<?> list) {
for (Object element : list) {
System.out.println(element);
}
}
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
printList(list1);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(100);
list2.add(200);
printList(list2);
}
}
q些代码说明了在printList函数中,List<?>表示各种cd的List对象。然而,h意,在声明的时候?? 通配W是不合法的Q像q样Q?BR>
List<?> myList = new ArrayList<?>(); // 不合?/FONT>
如果你想创徏一个接收Q何类型对象的ListQ你可以使用Object作ؓtype variableQ就像这P
List<Object> myList = new ArrayList<Object>();
在函C使用界限通配W?/P>
在之前的章节中,你学会了通过传递不同的type variables来创Z同JAVAcd的泛型,但ƈ不考虑type variables之间的承关pR在很多情况下,你想一个函数有不同的List参数。比如,你有一个函数getAverageQ他q回了一个List中成员的q_倹{然而,如果你把List<Number>作ؓetAverage的参敎ͼ你就没法传递List<Integer> 或List<Double>参数Q因为List<Number>和List<Integer> 和List<Double>不是同样的类型。你能用raw type 或用通配W,但这h法在compile timeq行安全cd查,因ؓ你能传递Q何Q何类型的ListQ比如List<String>的实例。你可以使用List<Number>作ؓ参数Q但是你只能传递List<Number>l函数。但q样׃你的函数功能减少Q因Z可能更多的时候要操作List<Integer>或List<Long>Q而不是List<Number>?/P>
J2SE5.0增加了一个规则来解决了这U约束,q个规则是允许你定义一个上?upper bound) type variable.在这U方式中Q你能传递一个类型或它的子类。在上面getAverage函数的例子中Q你能传递一个List<Number>或它的子cȝ实例Q比如List<Integer> or List<Float>?/P>
使用上界规则的语法这么定义的QGenericType<? extends upperBoundType>. 比如Q对getAverage函数的参敎ͼ你可以这么写List<? extends Number>. 下面例子说明了如何用这U规则?/P>
package com.brainysoftware.jdk5.app16;
import java.util.ArrayList;
import java.util.List;
public class BoundedWildcardTest {
public static double getAverage(List<? extends Number> numberList)
{
double total = 0.0;
for (Number number : numberList)
total += number.doubleValue();
return total/numberList.size();
}
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(3);
integerList.add(30);
integerList.add(300);
System.out.println(getAverage(integerList)); // 111.0
List<Double> doubleList = new ArrayList<Double>();
doubleList.add(3.0);
doubleList.add(33.0);
System.out.println(getAverage(doubleList)); // 18.0
}
}
׃有了上界规则Q上面例子中的getAverage函数允许你传递一个List<Number> 或一个type variable是Q何java.lang.Number子类的List?/P>
下界规则
关键字extends定义了一个type variable的上界。通过使用super关键字,我们可以定义一个type variable的下界,管通用的情况不多。比如,如果一个函数的参数是List<? super Integer>Q那么意味着你可以传递一个List<Integer>的实例或者Q何java.lang.Integer的超c?superclass)?/P>
创徏泛型c?/P>
前面的章节主要说明了如何使用泛型类Q特别是Collections framework中的cR现在我们开始学习如何写自己的泛型类?/P>
基本上,除了声明一些你惌使用的type variables外,一个泛型类和别的类没有什么区别。这些type variables位于cd后面?lt;>中。比如,下面的Point是个泛型类。一个Point对象代表了一个系l中的点Q它有横坐标和纵坐标。通过使Point泛型化,你能定义一个点实例的精程度。比如,一个Point对象需要非常精,你能把Double作ؓtype variable。否则,Integer 够了?/P>
package com.brainysoftware.jdk5.app16;
public class Point<T> {
T x;
T y;
public Point(T x, T y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public T getY() {
return y;
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
}
在这个例子中QT是Point的type variable 。T是getX和getY的返回值类型,也是setX和setY的参数类型。此外,构造函数结合两个T参数?/P>
使用pointcd像用别的类一栗比如,下面的例子创Z两个Point对象Qponint1和point2。前者把Integer作ؓtype variableQ而后者把Double作ؓtype variable?BR>
Point<Integer> point1 = new Point<Integer>(4, 2);
point1.setX(7);
Point<Double> point2 = new Point<Double>(1.3, 2.6);
point2.setX(109.91);
ȝ
泛型使代码在compile time有了更严格的cd查。特别是在Collections framework中,泛型有两个作用。第一Q他们增加了Ҏ集类?collection typesQ在compile time的类型检查,所以收集类所能持有的cd对传递给它的参数cd起了限制作用。比如你创徏了一个持有strings的java.util.List实例Q那么他将不能接受Integers或别的类型。其ơ,当你从一个收集中取得一个元素时Q泛型消除了cd转换的必要?/P>
泛型能够在没有type variable的情况下使用Q比如,作ؓraw types。这些措施让Java 5之前的代码能够运行在JRE 5中。但是,Ҏ的应用程序,你最好不要用raw typesQ因Z后Java可能不支持他们?/P>
你已l知道通过传递不同类型的type variablel泛型类可以产生不同的JAVAcd。就是说List<String>和List<Object>的类型是不同的。尽String是java.lang.Object。但是传递一个List<String>l一个参数是List<Object>的函C参数会生编译错误(compile errorQ。函数能?? 通配W其接受Q何类型的参数。List<?> 意味着Mcd的对象?/P>
最后,你已l看C写一个泛型类和别的一般JAVAcL有什么区别。你只需要在cd名称后面?lt;>中声明一pd的type variablesp了。这些type variables是q回值类型或者参数类型。根据惯例,一?BR>type variable用一个大写字母表C?/P>
public class test {
//static Logger logger = Logger.getLogger(test.class);
private static ClassLoader getTCL() throws IllegalAccessException,
InvocationTargetException {
// Are we running on a JDK 1.2 or later system?
Method method = null;
try {
method = Thread.class.getMethod("getContextClassLoader", null);
} catch (NoSuchMethodException e) {
// We are running on JDK 1.1
return null;
}
return (ClassLoader) method.invoke(Thread.currentThread(), null);
}
static public URL getResource(String resource) {
ClassLoader classLoader = null;
URL url = null;
try {
classLoader = getTCL();
} catch (IllegalAccessException e) {
// TODO 自动生成 catch ?BR> e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO 自动生成 catch ?BR> e.printStackTrace();
}
url = classLoader.getResource(resource);
return url;
}
public static void main(String argv[]) {
// BasicConfigurator.configure();
// logger.debug("Hello world.");
// logger.info("What a beatiful day.");
Properties props = new Properties();
java.net.URL configURL;
try {
configURL = getResource("b.txt");
props.load(configURL.openStream());
String value = props.getProperty("a");
System.out.print(value);
} catch (MalformedURLException e) {
// TODO 自动生成 catch ?BR> e.printStackTrace();
} catch (IOException e1) {
// TODO 自动生成 catch ?BR> e1.printStackTrace();
}
}
}
in properties file,# is remark