Поиск по классу java

Поиск класса объекта в Java

Краткое и практическое руководство по поиску класса объекта в Java.

1. Обзор

В этой статье мы рассмотрим различные способы поиска класса объекта в Java.

2. Использование метода getClass()

Первый метод, который мы проверим, – это метод getClass () .

Во-первых, давайте взглянем на наш код. Мы напишем Пользователь класс:

Теперь давайте создадим Кредитор класс, который расширяет Пользователя :

public class Lender extends User < // implementation details >

Аналогично, мы создадим класс Заемщик , который также расширяет Пользователя :

public class Borrower extends User < // implementation details >

Метод getClass() просто возвращает класс времени выполнения объекта , который мы оцениваем , следовательно, мы не рассматриваем наследование.

Как мы видим, getClass() показывает, что класс нашего объекта lender имеет тип Lender , но не тип User :

@Test public void givenLender_whenGetClass_thenEqualsLenderType()

3. Использование метода isInstance()

При использовании метода isInstance() мы проверяем, относится ли объект к определенному типу , и по типу мы говорим либо о классе, либо об интерфейсе.

Этот метод вернет true , если наш объект, отправленный в качестве аргумента метода, пройдет тест IS-A для класса или типа интерфейса .

Мы можем использовать метод isInstance() для проверки класса объекта во время выполнения. Кроме того, isInstance () |/также обрабатывает автобокс .

Если мы проверим следующий код, мы обнаружим, что код не компилируется:

@Ignore @Test public void givenBorrower_whenDoubleOrNotString_thenRequestLoan() < Borrower borrower = new Borrower(); double amount = 100.0; if(amount instanceof Double) < // Compilation error, no autoboxing borrower.requestLoan(amount); >if(!(amount instanceof String)) < // Compilation error, incompatible operands borrower.requestLoan(amount); >>

Давайте проверим автобокс в действии с помощью метода isInstance() :

@Test public void givenBorrower_whenLoanAmountIsDouble_thenRequestLoan() < Borrower borrower = new Borrower(); double amount = 100.0; if(Double.class.isInstance(amount)) < // No compilation error borrower.requestLoan(amount); >assertEquals(100, borrower.getTotalLoanAmount()); >

Теперь давайте попробуем оценить наш объект во время выполнения:

@Test public void givenBorrower_whenLoanAmountIsNotString_thenRequestLoan() < Borrower borrower = new Borrower(); Double amount = 100.0; if(!String.class.isInstance(amount)) < // No compilation error borrower.requestLoan(amount); >assertEquals(100, borrower.getTotalLoanAmount()); >

Мы также можем использовать isInstance() для проверки возможности приведения объекта в другой класс перед его приведением :

@Test public void givenUser_whenIsInstanceOfLender_thenDowncast() < User user = new Lender(); Lender lender = null; if(Lender.class.isInstance(user)) < lender = (Lender) user; >assertNotNull(lender); >

Когда мы используем метод isInstance () , мы защищаем нашу программу от попыток незаконного понижения, хотя использование оператора | instanceof в этом случае будет более плавным. Давайте проверим это дальше.

4. Использование оператора instanceof

Аналогично методу isInstance () , оператор instanceof возвращает true , если оцениваемый объект принадлежит к заданному типу — другими словами, если наш объект, на который ссылается оператор с левой стороны, проходит тест IS-A для класса или типа интерфейса с правой стороны .

Мы можем оценить, является ли объект Кредитор типом Кредитор и типом Пользователь :

@Test public void givenLender_whenInstanceOf_thenReturnTrue()

Чтобы получить более подробное представление о том, как работает оператор instanceof , мы можем найти дополнительную информацию в нашей статье Java instanceOf Operator .

5. Заключение

В этой статье мы рассмотрели три различных способа поиска класса объекта в Java: метод getClass () , метод isInstance() и оператор instanceof .

Как обычно, полные образцы кода доступны на GitHub .

Читайте ещё по теме:

Источник

Discovering Class Members

There are two categories of methods provided in Class for accessing fields, methods, and constructors: methods which enumerate these members and methods which search for particular members. Also there are distinct methods for accessing members declared directly on the class versus methods which search the superinterfaces and superclasses for inherited members. The following tables provide a summary of all the member-locating methods and their characteristics.

Class Methods for Locating Fields

Class API List of members? Inherited members? Private members?
getDeclaredField() no no yes
getField() no yes no
getDeclaredFields() yes no yes
getFields() yes yes no

Class Methods for Locating Methods

Class API List of members? Inherited members? Private members?
getDeclaredMethod() no no yes
getMethod() no yes no
getDeclaredMethods() yes no yes
getMethods() yes yes no

Class Methods for Locating Constructors

Class API List of members? Inherited members? Private members?
getDeclaredConstructor() no N/A 1 yes
getConstructor() no N/A 1 no
getDeclaredConstructors() yes N/A 1 yes
getConstructors() yes N/A 1 no

1 Constructors are not inherited.

Given a class name and an indication of which members are of interest, the ClassSpy example uses the get*s() methods to determine the list of all public elements, including any which are inherited.

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Member; import static java.lang.System.out; enum ClassMember < CONSTRUCTOR, FIELD, METHOD, CLASS, ALL >public class ClassSpy < public static void main(String. args) < try < Classc = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); Package p = c.getPackage(); out.format("Package:%n %s%n%n", (p != null ? p.getName() : "-- No Package --")); for (int i = 1; i < args.length; i++) < switch (ClassMember.valueOf(args[i])) < case CONSTRUCTOR: printMembers(c.getConstructors(), "Constructor"); break; case FIELD: printMembers(c.getFields(), "Fields"); break; case METHOD: printMembers(c.getMethods(), "Methods"); break; case CLASS: printClasses(c); break; case ALL: printMembers(c.getConstructors(), "Constuctors"); printMembers(c.getFields(), "Fields"); printMembers(c.getMethods(), "Methods"); printClasses(c); break; default: assert false; >> // production code should handle these exceptions more gracefully > catch (ClassNotFoundException x) < x.printStackTrace(); >> private static void printMembers(Member[] mbrs, String s) < out.format("%s:%n", s); for (Member mbr : mbrs) < if (mbr instanceof Field) out.format(" %s%n", ((Field)mbr).toGenericString()); else if (mbr instanceof Constructor) out.format(" %s%n", ((Constructor)mbr).toGenericString()); else if (mbr instanceof Method) out.format(" %s%n", ((Method)mbr).toGenericString()); >if (mbrs.length == 0) out.format(" -- No %s --%n", s); out.format("%n"); > private static void printClasses(Class c) < out.format("Classes:%n"); Class[] clss = c.getClasses(); for (Class cls : clss) out.format(" %s%n", cls.getCanonicalName()); if (clss.length == 0) out.format(" -- No member interfaces, classes, or enums --%n"); out.format("%n"); > >

This example is relatively compact; however the printMembers() method is slightly awkward due to the fact that the java.lang.reflect.Member interface has existed since the earliest implementations of reflection and it could not be modified to include the more useful getGenericString() method when generics were introduced. The only alternatives are to test and cast as shown, replace this method with printConstructors() , printFields() , and printMethods() , or to be satisfied with the relatively spare results of Member.getName() .

Samples of the output and their interpretation follows. User input is in italics.

$ java ClassSpy java.lang.ClassCastException CONSTRUCTOR Class: java.lang.ClassCastException Package: java.lang Constructor: public java.lang.ClassCastException() public java.lang.ClassCastException(java.lang.String)

Since constructors are not inherited, the exception chaining mechanism constructors (those with a Throwable parameter) which are defined in the immediate super class RuntimeException and other super classes are not found.

$ java ClassSpy java.nio.channels.ReadableByteChannel METHOD Class: java.nio.channels.ReadableByteChannel Package: java.nio.channels Methods: public abstract int java.nio.channels.ReadableByteChannel.read (java.nio.ByteBuffer) throws java.io.IOException public abstract void java.nio.channels.Channel.close() throws java.io.IOException public abstract boolean java.nio.channels.Channel.isOpen()

The interface java.nio.channels.ReadableByteChannel defines read() . The remaining methods are inherited from a super interface. This code could easily be modified to list only those methods that are actually declared in the class by replacing get*s() with getDeclared*s() .

$ java ClassSpy ClassMember FIELD METHOD Class: ClassMember Package: -- No Package -- Fields: public static final ClassMember ClassMember.CONSTRUCTOR public static final ClassMember ClassMember.FIELD public static final ClassMember ClassMember.METHOD public static final ClassMember ClassMember.CLASS public static final ClassMember ClassMember.ALL Methods: public static ClassMember ClassMember.valueOf(java.lang.String) public static ClassMember[] ClassMember.values() public final int java.lang.Enum.hashCode() public final int java.lang.Enum.compareTo(E) public int java.lang.Enum.compareTo(java.lang.Object) public final java.lang.String java.lang.Enum.name() public final boolean java.lang.Enum.equals(java.lang.Object) public java.lang.String java.lang.Enum.toString() public static T java.lang.Enum.valueOf (java.lang.Class,java.lang.String) public final java.lang.Class java.lang.Enum.getDeclaringClass() public final int java.lang.Enum.ordinal() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() hrows java.lang.InterruptedException public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()

In the fields portion of these results, enum constants are listed. While these are technically fields, it might be useful to distinguish them from other fields. This example could be modified to use java.lang.reflect.Field.isEnumConstant() for this purpose. The EnumSpy example in a later section of this trail, Examining Enums, contains a possible implementation.

In the methods section of the output, observe that the method name includes the name of the declaring class. Thus, the toString() method is implemented by Enum , not inherited from Object . The code could be amended to make this more obvious by using Field.getDeclaringClass() . The following fragment illustrates part of a potential solution.

Источник

Инструменты для поиска аннотированных классов в Java

В статье приведен небольшой обзор трех инструментов для поиска аннотированных классов в java проекте.

image

@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation <> @MyAnnotation public class Bar <> @MyAnnotation public class Foo <>

Spring

В Spring для этих целей служит ClassPathScanningCandidateComponentProvider.

имеет множество других фильтров (для типа, для методов и т.д.)

Пример

@Benchmark public void spring() < ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class)); Listcollect = scanner .findCandidateComponents("edu.pqdn.scanner") .stream() .map(BeanDefinition::getBeanClassName) .filter(Objects::nonNull) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); >

Reflections

  • get all subtypes of some type
  • get all types/members annotated with some annotation
  • get all resources matching a regular expression
  • get all methods with specific signature including parameters, parameter annotations and return type
 org.reflections reflections 0.9.11 

Пример

@Benchmark public void reflection() < Reflections reflections = new Reflections("edu.pqdn.scanner"); Set> set = reflections.getTypesAnnotatedWith(MyAnnotation.class); List collect = set.stream() .map(Class::getCanonicalName) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); >

classindex

 org.atteo.classindex classindex 3.4 
@IndexMyAnnotated public @interface IndexerAnnotation <> @IndexerMyAnnotation public class Bar <> @IndexerMyAnnotation public class Foo <>

Пример

@Benchmark public void indexer() < Iterable> iterable = ClassIndex.getAnnotated(IndexerMyAnnotation.class); List list = StreamSupport.stream(iterable.spliterator(), false) .map(aClass -> aClass.getCanonicalName()) .collect(Collectors.toList()); assertEquals(list.size(), 2); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Bar")); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Foo")); >

JMH

Benchmark Mode Cnt Score Error Units ScannerBenchmark.indexer avgt 50 0,100 ? 0,001 ms/op ScannerBenchmark.reflection avgt 50 5,157 ? 0,047 ms/op ScannerBenchmark.spring avgt 50 4,706 ? 0,294 ms/op

Заключение

Как видно indexer самый производительный инструмент, однако, аннотации по которым производится поиск должны иметь стереотип @IndexAnnotated.

Другие два инструмента работают заметно медленнее, однако для их работы никакого шаманства с кодом производить не надо. Недостаток полностью нивелируется, если поиск необходим только на старте приложения

Источник

Читайте также:  Последовательность фибоначчи формула python
Оцените статью