java 从超类实例创建实例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6924974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create instance from superclass instance
提问by didi_X8
Consider the following case:
考虑以下情况:
class A {
int x;
int y;
}
class B extends A {
int z;
}
Now, somewhere in the code this classes are used like this:
现在,在代码的某个地方,这些类是这样使用的:
A objA = getAFromSomewhere();
B objB = null;
And in a certain situation I want to do something like
在某种情况下,我想做一些类似的事情
objB = objA; // can't do this
objB.z = someZ;
Of course the real objects are a bit more complicated, so it's not just about copying two ints. But they aren't overly complex either.
当然,真正的对象要复杂一些,所以不仅仅是复制两个整数。但它们也不是太复杂。
I know I can write a constructor for B like this:
我知道我可以像这样为 B 编写一个构造函数:
public B(A anA) {
this.a = anA.a;
this.b = anA.b;
this.z = 0;
}
But if that's really the only way, I prefer merging the additional members of B into A.
但如果那真的是唯一的方法,我更喜欢将 B 的其他成员合并到 A 中。
update considering the answers
更新考虑答案
My question was not clear enough. I understand that objB = objA; can't work (thus I asked for "something like", meaning something with comparable code complexity) and I know about the issues with shallow vs deep copies.
What I was looking for is a possibility to copy the members of a base class (let's say using clone()). You may understand that copying every member manually is a bad solution as it adds complexity and redundancy to the code. Thanks for your replies anyway!
我的问题不够清楚。我明白 objB = objA; 不能工作(因此我要求“类似的东西”,意思是具有可比代码复杂性的东西)并且我知道浅拷贝和深拷贝的问题。
我正在寻找的是复制基类成员的可能性(假设使用 clone())。您可能理解手动复制每个成员是一个糟糕的解决方案,因为它增加了代码的复杂性和冗余。无论如何,感谢您的回复!
采纳答案by Jon Skeet
There's no trivial solution to this because there's no one-size-fits-all solution. Basically you don't have all the information within a B
, so you can't guarantee you would have a "sensible" B
object.
对此没有简单的解决方案,因为没有一刀切的解决方案。基本上,您没有 . 中的所有信息B
,因此您不能保证您将拥有一个“合理”的B
对象。
You probablyjust want to create a constructor in B
which takes an A
and copies all the A
data into the new B
.
您可能只想创建一个构造函数,B
其中接受一个A
并将所有A
数据复制到新的B
.
回答by Alnitak
There isa (relatively) trivial solution!
这里是一个(相对)平凡解!
Implement a constructor in class B
that takes an instance of class A
and copies the fields.
实现一个构造函数,class B
它接受一个实例class A
并复制字段。
One of the reasons there's no genericsolution in the language itself is because of the problem of deep copying.
语言本身没有通用解决方案的原因之一是深度复制的问题。
For example, if the source object contains further Objects
, as opposed to plain types, what would the generic copy operator do? Just copy the reference (giving a shallow copy), or make real copies?
例如,如果源对象包含更多Objects
,而不是普通类型,那么泛型复制运算符会做什么?只是复制参考(提供浅拷贝),还是制作真正的副本?
What then if one of those objects is a Collection
? Should it also copy every element of the collection, too?
那么如果这些对象之一是 aCollection
呢?它还应该复制集合的每个元素吗?
The only logical conclusion would be to perform a shallowcopy, but then you haven't really got a copy at all.
唯一合乎逻辑的结论是执行浅拷贝,但是您根本没有真正得到副本。
回答by JTP
If you're not scared of commons-beanutils you can use PropertyUtils
如果你不害怕 commons-beanutils 你可以使用 PropertyUtils
import org.apache.commons.beanutils.PropertyUtils;
class B extends A {
B(final A a) {
try {
PropertyUtils.copyProperties(this, a);
}
catch (Exception e) {
}
}
}
回答by user1098932
...not because this is what people should do but more because I felt like a challenge, here is some test code which does a simple copy of the objects (using setter and getter methods):
...不是因为这是人们应该做的,而是因为我觉得这是一个挑战,这里有一些测试代码,它对对象进行了简单的复制(使用 setter 和 getter 方法):
import java.lang.reflect.Method;
import org.junit.Test;
public class ObjectUtils {
@Test
public void test() {
A a = new A();
B b = new B();
a.setX(1);
a.setY(2);
this.copyProperties(a, b);
}
private void copyProperties(Object obja, Object objb) {
Method m[] = obja.getClass().getDeclaredMethods();
for(int i=0;i<m.length;i++) {
try {
String name = m[i].getName();
if(name.startsWith("get") || name.startsWith("is")) {
Class rtype = m[i].getReturnType();
String setter = name.replaceFirst("^(get|is)","set");
Class s = objb.getClass();
Method method = s.getMethod(setter,rtype);
Object[] args = new Object[1];
args[0] = m[i].invoke(obja);
method.invoke(objb,args[0]);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
class A {
int x;
int y;
/**
* @return the x
*/
public int getX() {
return x;
}
/**
* @param x the x to set
*/
public void setX(int x) {
this.x = x;
}
/**
* @return the y
*/
public int getY() {
return y;
}
/**
* @param y the y to set
*/
public void setY(int y) {
this.y = y;
}
}
class B extends A {
int z;
/**
* @return the z
*/
public int getZ() {
return z;
}
/**
* @param z the z to set
*/
public void setZ(int z) {
this.z = z;
}
}
}
回答by Gilbert Le Blanc
Perhaps you could do this:
也许你可以这样做:
class A {
int x;
int y;
A(A a) {
this.x = a.x;
this.y = a.y;
}
}
class B extends A {
int z;
B(A a) {
super(a);
z = 0;
}
}
You're still listing every field, but only once per class.
您仍在列出每个字段,但每个类只列出一次。
回答by AlexR
I am shocked too. :)
我也很震惊。:)
You really cannot do this: objB = objA;
.
Because Renault and BMW are cars but not all cars are BMW.
你真的不能做到这一点:objB = objA;
。因为雷诺和宝马都是汽车,但并非所有汽车都是宝马。
Thank about A as Car, B as BMW.
感谢 A 为汽车,B 为宝马。
Now you say:
现在你说:
Car car = new Renault();
BMV bmv = car; // you cannot do this. This is exactly your case.
回答by user3132194
If you do not need full functionality of A, there is also an option to create class B, holding internal copy of A instance and implementing some minimal subset of methods via C interface by proxying them to instance.
如果您不需要 A 的全部功能,还可以选择创建类 B,保存 A 实例的内部副本,并通过将它们代理到实例来通过 C 接口实现一些最小的方法子集。
class A implements IC {
int x;
int y;
public C() {
...
}
}
class B implements IC {
private A _a;
public B(A a) {
_a = a;
}
public C() {
_a.C();
}
}
回答by Rohit Ganeshan
Assuming that your class A has a very neat and clean setter and getter method naming convention like
setXXX(Object xxx)
and corrresponding getXXX()
which returns the same thing (Object xxx ) as a param passed to setXXX()
假设你的类 A 有一个非常整洁干净的 setter 和 getter 方法命名约定,如
setXXX(Object xxx)
和相应的getXXX()
,它返回与传递给的参数相同的东西(对象 xxx )setXXX()
I have written a utility method using reflection
我写了一个使用反射的实用方法
public static B createSubclassInstance(A a) throws SecurityException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Method[] aMethods = Class.forName("package.A").getDeclaredMethods();
B b = new B();
for (Method aMethod : aMethods) {
String aMethodName = aMethod.getName();
Class param = aMethod.getReturnType();
if (methodName.startsWith("get")){
String setterMethodName = methodName.replaceFirst("get", "set");
Method bMethod = Class.forName("package.B").getMethod(setterMethodName);
Object retValA = aMethod.invoke(a,null);
bMethod.invoke(b,retValA);
}
}
return b;
}
回答by Matthias Ronge
If you change your method to create B
objects, you can just do what you want using:
如果您更改创建B
对象的方法,则可以使用以下方法执行所需的操作:
objB = (B) objA;
objB.z = someZ;
This can even be inlined, but you need parentheses:
这甚至可以内联,但你需要括号:
((B) objA).z = someZ;
If not, you have to go the long way using constructors:
如果没有,您必须使用构造函数走很长的路:
objB = new B(objA);
objB.z = someZ;
In this case I would recommend to copy the fields of the superclass in the superclass. Else, if you add a field to that class later, you may forget to change the copying more easily.
在这种情况下,我建议在超类中复制超类的字段。否则,如果您稍后向该类添加字段,您可能会更容易忘记更改副本。
class A {
int x;
int y;
public A(A objA) {
x = objA.x;
y = objA.y;
}
}
class B extends A {
int z;
public B(A objA) {
super(objA);
}
}
I prefer merging the additional members of B into A.
我更喜欢将 B 的其他成员合并到 A 中。
You cando this if your classes A
and B
share the same package
or if the variables in your A
class are declared as protected
. Then you can just access the fields of the superclass.
你可以,如果你的类做到这一点A
,并B
共享相同的package
或者如果您的变量A
类被声明为protected
。然后你就可以访问超类的字段了。
class A {
protected int x;
protected int y;
}
class B extends A {
int z;
void merge(A a){
super.x = a.x;
y = a.y; // you do not *need* to use the super keyword, but it is a good hint to
// yourself if you read your program later and might wonder ‘where is
// that y declared?'
}
}
Useage, of course, is:
用途当然是:
objB = new B();
objB.merge(objA);
objB.z = someZ;
回答by Low Flying Pelican
I think best way is to use a factory method to create B objects from A objects.
我认为最好的方法是使用工厂方法从 A 对象创建 B 对象。
class BFactory
{
public static B createB(A a)
{
B b = new B();
copy(a,b);
return b;
}
private static <X,Y> void copy(X src,Y dest) throws Exception
{
List<Field> aFields = getAllFields(src.getClass());
List<Field> bFields = getAllFields(dest.getClass());
for (Field aField : aFields) {
aField.setAccessible(true);
for (Field bField : bFields) {
bField.setAccessible(true);
if (aField.getName().equals(bField.getName()))
{
bField.set(dest, aField.get(src));
}
}
}
}
private static List<Field> getAllFields(Class type)
{
ArrayList<Field> allFields = new ArrayList<Field>();
while (type != Object.class)
{
Collections.addAll(allFields, type.getDeclaredFields());
type = type.getSuperclass();
}
return allFields;
}
}