`
xly_971223
  • 浏览: 1263530 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

提问:Java5泛型的T.class的获取

阅读更多
需求:
将A B C类对应的三个对象a b c保存在http session中,并对每个类进行封装
如下

public class AHelper {
	private A a;
	private HttpServletRequest request;
	
	public AHelper(HttpServletRequest request) {
		this.request = request;
		
		a = (A)request.getSession().getAttribute("a_key");
		if(a == null){
			a = new A();
		}
	}
	
	public A get(){
		return a;
	}
}

public class BHelper {
	private B b;
	private HttpServletRequest request;
	
	public BHelper(HttpServletRequest request) {
		this.request = request;
		
		b = (B)request.getSession().getAttribute("b_key");
		if(a == null){
			b = new B();
		}
	}
	
	public B get(){
		return b;
	}
}


CHelper 类似

现在想用jdk5的范型将上面的3个类合并成一个 如下:
public class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;

	public BaseHelper(HttpServletRequest request, String key) {
		this.request = request;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
			//怎样获取T.class? 
		}
	}
	
	public T get(){
		return object;
	}
}



问题: 怎样获取T.class?
http://www.blogjava.net/calvin/archive/2006/04/28/43830.html中有介绍获取T.class的方法,但是要求先写一个父类,然后通过继承来实现
这样做需要4个类才能实现:一个父类和3个子类
请问高手们 能不能通过一个类或者有限个类来就解决这类问题?
分享到:
评论
20 楼 lsy 2007-04-07  
我来补充下ecsoftcn说的需要带参数得方法
public class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;

	public BaseHelper(HttpServletRequest request, String key, Class<T> clazz, String[] args, Class<String>... argTypes) {
		this.request = request;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
		  Constructor constructor ;
		  try{
			constructor = clazz.getConstructor(argTypes);
			object = constructor.newInstance(args);
		  }
		  catch(NoSuchMethodException e){}
		  catch(IllegalAccessException e){}		
		  catch(InvocationTargetException e){}
		  catch(InstantiationException e){}
		}
	}
	
	public T get(){
		return object;
	}
}

19 楼 hbcui1984 2007-04-07  
关注中,唉,看看强人的代码,才知道自己有多烂
18 楼 ecsoftcn 2007-04-07  
xly_971223 写道
需求:

现在想用jdk5的范型将上面的3个类合并成一个 如下:
public class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;

	public BaseHelper(HttpServletRequest request, String key) {
		this.request = request;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
			//怎样获取T.class? 
		}
	}
	
	public T get(){
		return object;
	}
}



问题: 怎样获取T.class?
http://www.blogjava.net/calvin/archive/2006/04/28/43830.html中有介绍获取T.class的方法,但是要求先写一个父类,然后通过继承来实现
这样做需要4个类才能实现:一个父类和3个子类
请问高手们 能不能通过一个类或者有限个类来就解决这类问题?


----------------------------------------------------------------

T.class是无法获取了,这里提供一个稍微"变态"一点的办法:

public class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;

	public BaseHelper(HttpServletRequest request, String key, Class<T> clazz) {
		this.request = request;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
			object = clazz.newInstance();
		}
	}
	
	public T get(){
		return object;
	}
}


当然,这样用的前题是你的类里面要有一个无参数的构造函数.

如果你需要参数化你的构造类,那么可以把参数也传进去,如你有一个带4个String类型参数的构造函数,那么你可以这样定义:

public class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;

	public BaseHelper(HttpServletRequest request, String key, Class<T> clazz, String... param) {
		this.request = request;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
			//初始化 object
		}
	}
	
	public T get(){
		return object;
	}
}


17 楼 xly_971223 2007-04-06  
java对这个问题的解决,就现在看来似乎是无能为力
16 楼 haihai 2007-04-06  
关注,我也想过这个问题,一直没有好的解决办法。
15 楼 fhjxp 2007-04-06  
是不是可以这样理解:泛型像C里面的宏一样,根本就不是Java语言本身的东西,仅仅是为java增加编译检查手段而已,Java的类加载运行时,根本就没有泛型的概念,更不用说动态获取T.class了
14 楼 jianfeng008cn 2007-03-18  
如上代码,编译期检查而已,运行期已没有T的概念,所以T.class是得不到的,这和大部分的逻辑是不相符合的,java的一个奇怪的语法吧
13 楼 jianfeng008cn 2007-03-14  


引用


public class BaseHelper<T> {     
       public BaseHelper() {} 
}

BaseHelper<Customer>  bh = new BaseHelper<Customer>();





各位的意思就是说 如上一段代码是没办法知道T的运行时真实类型了?
刚找了半天也没发现怎么样可以在我上面的代码所示的情况下 ,得到 T.class

如果这样,是不是泛型在设计上有点奇怪呢?
按照我的理解,信息一旦体现在实例初始化了,就应该能够取到才合理,希望得到一些指点哦。

12 楼 bencode 2007-02-03  
引用
xly_971223说
对 编译后的class文件中是没有T的,所有用这个这种方式是取不到T.class的
ruby等动态语言是不是能够解决这个问题呢?


Ruby根本不存在这种问题.
11 楼 javatar 2007-02-03  
江南白衣 写道

Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];


真是太绝了,我在没看到这个帖之前,也一直想着这个问题。
因为我想让每个Dao只处理一个Entity,
怎样将该Dao所处理Entity的class元数据传到BaseDao一直没想到好办法,
俗套的办法只好用构造函数传入 BaseDao(Class<T> entityClass)
或使用模板方法模式 abstract Class<T> getEntityClass();
看了上面的实现,看来是自己对反射没学好。
10 楼 xly_971223 2007-02-01  
bencode 写道
嗯, JAVA的泛形实现采用的是"擦除法",意味着编译后,其实T根本不存在.

所以楼主的泛形代码,基本上和下面这段等效"

public class BaseHelper {   
    private Object object = null;   
    private HttpServletRequest request;   
  
    public BaseHelper(HttpServletRequest request, String key) {   
        this.request = request;   
           
        object = request.getSession().getAttribute(key);   
        if(object == null){   
            //怎样获取T.class?  
            // T在哪里? 嘿嘿
        }   
    }   
       
    public T get(){   
        return object;   
    }   
}   
  


只不过是在编码时,方便一些.

所以根据形别参数是构造不出具体的对象的.
.
对 编译后的class文件中是没有T的,所有用这个这种方式是取不到T.class的
ruby等动态语言是不是能够解决这个问题呢?
9 楼 bencode 2007-01-31  
嗯, JAVA的泛形实现采用的是"擦除法",意味着编译后,其实T根本不存在.

所以楼主的泛形代码,基本上和下面这段等效"

public class BaseHelper {   
    private Object object = null;   
    private HttpServletRequest request;   
  
    public BaseHelper(HttpServletRequest request, String key) {   
        this.request = request;   
           
        object = request.getSession().getAttribute(key);   
        if(object == null){   
            //怎样获取T.class?  
            // T在哪里? 嘿嘿
        }   
    }   
       
    public T get(){   
        return object;   
    }   
}   
  


只不过是在编码时,方便一些.

所以根据形别参数是构造不出具体的对象的.
8 楼 Qieqie 2007-01-30  
我的了解是这样的,所谓T只是用来编写程序时使用的,方便写程序时使用,使能够在编译器发现类型cast的出错,从而减少调试麻烦。类编译后就不会有T这种概念了。所以不存在T.class这个东西。他不是一个类。

编写程序时,使用泛型,就代表了类型的灵活性,所以其class不是死的。要获取他的具体class,只能使用instance.getClass()方法
7 楼 luanma 2007-01-30  
/汗
你把代码改改,原代码里面的父类改称自己普通类不就OK了?!

你把
Type genType = clazz.getGenericSuperclass();


改成
Type genType = clazz;


试试
6 楼 huangpengxiao 2007-01-30  
protected abstract T initValue();  

sm = new BaseHelper<Product>(request, "x_key"){  
            protected Product initValue(){  
                return new Product();  
            }  
        };  

呵呵 强人 学了一招 闪
5 楼 xly_971223 2007-01-30  
complystill 写道
参考 ThreadLocal<T>, 定义一个抽象的 T initValue(); 方法, 然后使用的地方可以用匿名类实现.

参照ThreadLocal<T>完成如下
public abstract class BaseHelper<T> {
	private T object = null;
	private HttpServletRequest request;
	private String key;


	public BaseHelper(HttpServletRequest request, String key) {
		this.request = request;
		this.key = key;
		
		object = (T)request.getSession().getAttribute(key);
		if(object == null){
			object = initValue();
		}
	}
	
	public T get(){
		return object;
	}
	
	protected abstract T initValue();
}

public class BaseHelperTest extends TestCase {
	private BaseHelper<Product> sm;
	
	protected void setUp() throws Exception {
		HttpServletRequest request = new MockHttpServletRequest();
		
		sm = new BaseHelper<Product>(request, "x_key"){
			protected Product initValue(){
				return new Product();
			}
		};
	}

	protected void tearDown() throws Exception {
		super.tearDown();
	}

	/*
	 * Test method for 'com.ecc.beauty.common.page.SessionManager.getAttrbute(String)'
	 */
	public void testGet() {
		assertNotNull(sm.get());
	}

}


这种方式可以实现一个类代替 A B C等一系列类,但是在每一个用到的地方都写这样一段代码感觉不够优雅
sm = new BaseHelper<Product>(request, "x_key"){
			protected Product initValue(){
				return new Product();
			}
		};



不知道有没有更好的解决方式?
4 楼 xly_971223 2007-01-30  
luanma 写道
springside 里面的一段代码:
package com.j99view.razor.helper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Generics的util类,
 *
 * @author sshwsfc
 */
public class GenericsUtils {
	private static Log log = LogFactory.getLog(GenericsUtils.class);

	private GenericsUtils() {
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型.
	 * 如public BookManager extends GenricManager<Book>
	 *
	 * @param clazz The class to introspect
	 * @return the first generic declaration, or <code>Object.class</code> if cannot be determined
	 */
	public static Class getSuperClassGenricType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型.
	 * 如public BookManager extends GenricManager<Book>
	 *
	 * @param clazz clazz The class to introspect
	 * @param index the Index of the generic ddeclaration,start from 0.
	 */
	public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}
		return (Class) params[index];
	}
}

采用这种方式需要先定义一个带范型参数的父类,然后通过继承才能获得这个T.class,,A B C都需要继承这个父类,所以不能从根本上解决问题。
3 楼 luanma 2007-01-30  
springside 里面的一段代码:
package com.j99view.razor.helper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Generics的util类,
 *
 * @author sshwsfc
 */
public class GenericsUtils {
	private static Log log = LogFactory.getLog(GenericsUtils.class);

	private GenericsUtils() {
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型.
	 * 如public BookManager extends GenricManager<Book>
	 *
	 * @param clazz The class to introspect
	 * @return the first generic declaration, or <code>Object.class</code> if cannot be determined
	 */
	public static Class getSuperClassGenricType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型.
	 * 如public BookManager extends GenricManager<Book>
	 *
	 * @param clazz clazz The class to introspect
	 * @param index the Index of the generic ddeclaration,start from 0.
	 */
	public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}
		return (Class) params[index];
	}
}
2 楼 icewubin 2007-01-29  
你不是定义了object,所以只要写object.class不就行了么?
1 楼 歆渊 2007-01-29  
参考 ThreadLocal<T>, 定义一个抽象的 T initValue(); 方法, 然后使用的地方可以用匿名类实现.

相关推荐

Global site tag (gtag.js) - Google Analytics