Đây là một cách khá đơn giản để thực hiện việc này. getConstructorForArgs
-method đi qua tất cả các hàm tạo trong lớp đã cho và kiểm tra xem các tham số của hàm tạo có khớp với các tham số đã cho hay không (lưu ý rằng các tham số đã cho phải theo cùng thứ tự như trong hàm tạo). Việc triển khai các giao diện và các lớp con cũng hoạt động, vì "khả năng tương thích" được kiểm tra bằng cách gọi isAssignableFrom
cho đối số hàm tạo (là kiểu tham số đã gán có thể gán cho kiểu tham số trong hàm tạo).
public class ReflectionTest
{
public Constructor<?> getConstructorForArgs(Class<?> klass, Class[] args)
{
//Get all the constructors from given class
Constructor<?>[] constructors = klass.getConstructors();
for(Constructor<?> constructor : constructors)
{
//Walk through all the constructors, matching parameter amount and parameter types with given types (args)
Class<?>[] types = constructor.getParameterTypes();
if(types.length == args.length)
{
boolean argumentsMatch = true;
for(int i = 0; i < args.length; i++)
{
//Note that the types in args must be in same order as in the constructor if the checking is done this way
if(!types[i].isAssignableFrom(args[i]))
{
argumentsMatch = false;
break;
}
}
if(argumentsMatch)
{
//We found a matching constructor, return it
return constructor;
}
}
}
//No matching constructor
return null;
}
@Test
public void testGetConstructorForArgs()
{
//There's no constructor in HashSet that takes a String as a parameter
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{String.class}));
//There is a parameterless constructor in HashSet
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{}));
//There is a constructor in HashSet that takes int as parameter
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{int.class}));
//There is a constructor in HashSet that takes a Collection as it's parameter, test with Collection-interface
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{Collection.class}));
//There is a constructor in HashSet that takes a Collection as it's parameter, and HashSet itself is a Collection-implementation
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{HashSet.class}));
//There's no constructor in HashSet that takes an Object as a parameter
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{Object.class}));
//There is a constructor in HashSet that takes an int as first parameter and float as second
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{int.class, float.class}));
//There's no constructor in HashSet that takes an float as first parameter and int as second
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{float.class, int.class}));
}
}
Sửa: Lưu ý rằng giải pháp này là không hoàn hảo cho tất cả các trường hợp: nếu có hai nhà thầu, có một tham số đó là chuyển nhượng từ một loại tham số nhất định, người đầu tiên sẽ được chọn, ngay cả khi thứ hai là phù hợp hơn. Ví dụ: nếu SomeClass
sẽ có một hàm tạo có một số HashSet
(A Collection
-implementation) làm tham số và một hàm tạo tham số Collection
làm tham số, phương pháp có thể trả về một trong hai khi tìm kiếm một hàm tạo chấp nhận tham số HashSet
tùy thuộc vào điều gì đến trước khi lặp qua các lớp. Nếu cần phải làm việc cho những trường hợp như vậy, trước tiên bạn cần thu thập tất cả các ứng cử viên có thể, phù hợp với isAssignableFrom
và sau đó thực hiện phân tích sâu hơn cho các ứng cử viên để chọn ứng cử viên phù hợp nhất.
Wow !! Khá một chút mã.Bạn có thể vui lòng cung cấp một tệp clj có thể chạy được thể hiện cách gọi hàm 'find-best-constructors' với' HashSet' chẳng hạn. – viebel
Vâng, có ba ví dụ trong câu trả lời. Bạn có thể sao chép các biểu thức ở bên phải của 'user>' vào tệp REPL/của riêng bạn và xác minh rằng các giá trị được trả lại là như được quảng cáo. –
Bằng cách nào đó, tôi gặp lỗi khi nhập HashSet. Bạn có thể truy cập tập tin của tôi tại: [find-constructors.clj] (https://github.com/viebel/Learning/blob/master/clojure/find-constructors.clj). – viebel