Annotation and reflection

Posted by spacee on Sat, 25 Dec 2021 01:57:08 +0100

annotation

  • Annotation is a new technology introduced from JDK 5.0
  • effect:
    1. It is not the program itself, but the program can be explained (this is no different from the comment)
    2. It can be read by other programs (such as compiler, etc.)
  • Format of Annoation:
    Annotations exist in the code as "@ annotation name". You can also add some parameter values, such as:
    @SuppressWarnings(value="unchecked").
  • Use of Annoation
    It can be attached to package,class,method,field, etc., which is equivalent to adding additional auxiliary information to them. We can access these metadata through reflection mechanism programming.

Built in annotation

  • @Override: defined in Java In lang. override, this annotation is only applicable to modified methods, indicating that one method declaration intends to override another method declaration in the superclass.
  • @Deprecated: defined in Java In lang. deprecated, this annotation can be used for rhetorical devices, attributes, and classes to indicate that it is not encouraged, usually because it is dangerous or there is a better choice
  • @SuppressWarningsï¼› Defined in Java Lang. supplerswarnings, used to suppress compile time warnings.
    (different from the previous two comments, you need to add a parameter to use correctly. These parameters have been defined. SuppressWarnings("all"), SuppressWarnings("unchecked"), SuppressWarnings(value = {"unchecked", "depreciation"}),...)

Custom annotation, meta annotation

Meta annotation

  • Function: responsible for annotating other annotations. Java defines four standard meta annotation types, which are used to provide other annotation types for description.
  • These types and the classes they support are in Java You can find it in the lang.annotation package
    1.@Target: used to describe the scope of use of annotations (i.e. where the described annotations can be used)
    2.@Retention: indicates the level at which the annotation information needs to be saved. It is used to describe the annotation life cycle
    (Source<Class<RunTime)
    3.@Documented: note that the annotation will be included in javaDoc
    4.@Inherited: indicates that the subclass can inherit the annotation in the parent class

Custom annotation

  • Use @ interface to declare an annotation. Format: public @interface annotation name {definition content}
  • Each of these methods actually declares a configuration parameter
  • The name of the method is the parameter name
  • The return value type is the type of the parameter (return)
  • You can declare the default value of the parameter through default
  • If there is only one parameter member, the general parameter name is value
  • An annotation element must have a value. When defining an annotation element, we often use an empty string with 0 as the default value

Reflection mechanism

Overview of Java reflection mechanism

  • Static language and dynamic language
  • Reflection is the key to java being regarded as a dynamic language. The reflection mechanism allows the program to help the Reflection API obtain the internal information of any class during execution, and can directly operate the internal properties and methods of any object.
    Class c = Class.forName("java.lang.String")
  • After loading the class, a class object is generated in the method area of heap memory (a class has only one class object), which contains complete class structure information. You can see the structure of the class through this object. This object is like a mirror. Seeing the structure of the class through this mirror = = > is called reflection.

Class provided by reflection mechanism

  • Determine the class of any object at run time
  • Construct an object of any class at any time
  • Judge the member variables and methods of any class at run time
  • Get generic information at run time
  • Call the member variables and methods of any object at run time
  • Processing annotations at run time
  • Generate dynamic proxy
  • ...

Advantages and disadvantages

  • Advantages: it can dynamically create objects and compile, reflecting great flexibility
  • Disadvantages: it has an impact on performance. Using reflection is basically an interpretation operation. We can tell the JVM what we want to do and it meets our requirements. Such operations are always slower than performing the same operation directly.

Reflection related API

  • java.lang.Class: represents a class
  • java.lang.reflect.Method: represents the method of the class
  • java.lang.reflect.Field: represents the member variable of the class
  • java.lang.reflect.Constructor: represents the constructor of the class
  • ...

Understand Class class and get Class instance

Class class

The following methods are defined in the Object class, which will be inherited by all subclasses
public final Class getClass()

  • The type of the returned value of the above method is a Class class, which is the source of Java reflection. In fact, the so-called reflection is also well understood from the running results of the program, that is, the name of the Class can be obtained through object reflection
  • The information that can be obtained after the object looks in the mirror: the properties, methods and constructors of a class, and which interfaces a class implements.
    For some classes, JRE will retain an object of constant Class type. A Class object contains relevant information such as a specific structure (Class / interface / enum / annotation / primitive type / void / [])
    1. Class itself is a class
    2. Class objects can only be created by the system
    3. A loaded class has only one class instance in the JVM
    4. A class object corresponds to a class loaded into the JVM Class file
    5. Each Class instance will remember which Class instance it was generated from
    6. Through Class, you can completely get all the loaded data in a Class
    7. Class is the root of Reflection. For any class you want to dynamically load and run, you have to obtain the corresponding class object first

Common methods of Class

Method nameFunction description
static ClassforName(String name)Returns the class object of the specified class name
Object newInstanceCall the default structure function to return an instance of the Class object
getName()Returns the name of the entity (Class, interface, array Class or void) represented by this Class object
Class getSuperClass()Returns the class object of the parent class of the current class object
Class[] getinterfaces()Gets the interface of the current class object
ClassLoader getClassLoader()Returns the loader of this class
Construcotr[] getContstructors()Returns an array containing some Constructor objects
Method getMothed(String name,Class ... T)Returns a Method object whose formal parameter type is paramType
Field[] getDeclaredFields()Returns an array of Filed objects

Method of obtaining Class instance (summary)

  1. If a specific Class is known, it is obtained through the Class attribute of the Class. This method is the most safe and reliable, and the program performance is the highest.
    Class class = Person.class;
  2. If an instance of a Class is known, call the getClass() method of the instance to obtain the Class object
    Class class = person.getClass();
  3. If the full Class name of a Class is known, and the Class is in the Class path, it can be obtained through the static method forName() of Class class, and ClassNotFoundException can be thrown
    Class class = Class.forName("demo01.Student");
  4. The built - in basic data type can use the class name directly Type
  5. You can also use ClassLoader
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        //Method 1: obtained by object
        Class  c1 = person.getClass();
        System.out.println(c1.hashCode());

        //Method 2: forName
        Class  c2 = Class.forName("com.reflection.Student");
        System.out.println(c2.hashCode());

        //Method 3: pass the class name Class get
        Class c3 = Student.class;
        System.out.println(c3.hashCode());

        //Method 4: wrapper classes of basic built-in types have a Type attribute
        Class<Integer> type = Integer.TYPE;
        System.out.println(type);

        //Get parent type
        Class c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}
class Person{
   public String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

class Student extends Person{
    public Student() {
        this.name="student";
    }
}

The type that owns the Class object

  • Class: external class, member (member internal class, static internal class), local internal class, anonymous internal class
  • interface: interface
  • enum: Enumeration
  • Annotation: annotation @ interface
  • primitive type: basic data type
  • void
  • []: array
        Class c1 = Object.class;  //class
        Class c2 = Comparable.class; //Interface
        Class c3 = String[].class; //One dimensional array
        Class c4 = int[][].class; //Two dimensional array
        Class c5 = Override.class; //annotation
        Class c6 = ElementType.class; //enumeration
        Class c7 = Integer.class; //Basic data type
        Class c8 = void.class; //void
        Class c9 = Class.class;  //Class
        //AlT
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

        //As long as the element type is the same as the dimension, it is a Class
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());

Class loading and ClassLoader

java Memory Analysis

Class loading

  • Loading: the loading stage is the first stage of the class loading process. In this stage, the virtual machine needs to complete the following three things:
    1. Obtain the binary byte stream defining a class through the fully qualified name of the class.
    2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area.
    3. Generate a Java. Net file representing this class in the Java heap Lang. class object, as the access entry of these data in the method area.
  • Link: the process of merging the binaries of java classes into the running state of the JVM.
    1. Verification: ensure that the loaded class information complies with the JVM specification and there are no security problems
    2. Preparation: the stage of formally allocating memory for class variables (static) and setting the default initial value of class variables. These memory will be allocated in the method area
    3. Resolution: the process of replacing the symbolic reference (constant name) in the virtual machine constant pool with a direct reference (address)
  • initialization:
    1. The process of executing a class constructor () method. The class constructor () method is generated by the combination of the assignment actions of all variables in the class automatically collected at compile time and the statements in the static code block. (the class constructor is used to construct class information, not the constructor to construct the class object.).
    2. When initializing a class, if it is found that its parent class has not been initialized, its parent class initialization needs to be triggered first.
    3. Virtual chance ensures that the () methods of a class are locked and synchronized correctly in a multithreaded environment.

Class initialization

  • Active reference of class (class initialization must occur)
    1. When the virtual machine starts, first initialize the class where the main method is located
    2.new is an object of a class
    3. Call static members (except final constants) and static methods of the class
    4. Use Java The method of lang.reflect package makes reflection calls to the class
    5. When initializing a class, if its parent class is not initialized, its parent class will be initialized first
  • Passive reference of class (class initialization will not be sent)
    1. When accessing a static domain, only the class that actually declares the domain will be initialized. For example, when a static variable of a parent class is referenced through a subclass, the subclass will not be initialized
    2. Defining a class reference through an array will not trigger the initialization of this class
    3. Reference constants will not trigger the initialization of this class (constants are stored in the constant pool of the calling class in the connection phase)

Role of class loader

  • The function of class loading: load the bytecode content of the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a Java. Net file representing this class in the heap Lang. class object, as the access entry of class data in the method area.
  • Class caching: the standard javaSE class loader can find classes as required, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can recycle these class objects.
  • class loaders are used to load classes into memory. The JVM specification defines the following types of loaders.
    1. Boot class loader: written in C + +, it is the class loader of the JVM. It is responsible for the core library of the Java platform and is used to load the core class library. The loader cannot get directly.
    2. Extension class loader: it is responsible for the jar package or - D Java under jre/lib/ext directory The jar in the directory specified by ext.dirs is packaged into the working library.
    3. System class loader: responsible for java -classpath or - D Java class. The classes and jar s in the directory referred to in path are packaged into the work, which is the most commonly used loader.
        //Get system class loader
        ClassLoader systemClassLoager = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoager);

        //Gets the parent class loader -- > extension class loader of the system class loader
        ClassLoader parent = systemClassLoager.getParent();
        System.out.println(parent);

        //Get the parent class loader of the extension class loader -- > the root loader (C/C + +) java cannot get it
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);

        //Test which loader loads the current class
        ClassLoader classLoader = Class.forName("com.reflection.Demo07").getClassLoader();
        System.out.println(classLoader);
        //Test who loaded the jdk built-in classes
        classLoader = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);

        //How to get the path that the system class loader can load
        System.out.println(System.getProperty("java.class.path"));
        /*
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\charsets.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\deploy.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\access-bridge-32.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\cldrdata.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\dnsns.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\jaccess.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\jfxrt.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\localedata.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\nashorn.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\sunec.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\ext\zipfs.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\javaws.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\jce.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\jfr.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\jfxswt.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\jsse.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\management-agent.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\plugin.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\resources.jar;
        D:\BasicProgrammingTools\jdk1.8.0_144\jre\lib\rt.jar;
        D:\Project \ basic project \ java learning route \ annotation and reflection \ out\production \ annotation and reflection; D:\tool\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar
         */

        //Parent delegation mechanism: if the package you write already contains, it will use its own package instead of the package you write

//Get class information
public class Demo08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.reflection.User");

        //Get the name of the class
        System.out.println(c1.getName()); //Get package name + class name
        System.out.println(c1.getSimpleName()); //Get class name

        //Get the properties of the class
        System.out.println("====================================");
        Field[] fields = c1.getFields(); //Only public properties can be obtained
        fields = c1.getDeclaredFields(); //You can get all the attributes

        for (Field field : fields) {
            System.out.println(field);
        }

        //Or I specify the value of the property
        // Field name = c1.getField("name");  An error will be reported because the non-public attribute cannot be obtained
        Field name = c1.getDeclaredField("name"); //You can get the name of non-public attribute
        System.out.println(name);

        //Method to get class
        System.out.println("====================================");
        Method[] methods = c1.getMethods();  //Get all public methods of this class and its parent class
        for (Method method : methods) {
            System.out.println("getMethods:"+method);
        }
        methods = c1.getDeclaredMethods();  //Obtain all (non-public) methods of this class
        for (Method method : methods) {
            System.out.println("getDeclaredMethods:"+method);
        }

        //Gets the specified method parameters to prevent overloading
        System.out.println("====================================");
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //Get constructor
        System.out.println("====================================");
        Constructor[] constructors = c1.getConstructors(); //Get public constructor
        for (Constructor constructor : constructors) {
            System.out.println("getConstructors:"+constructors);
        }
        constructors = c1.getDeclaredConstructors(); //Get all constructors
        for (Constructor constructor : constructors) {
            System.out.println("getDeclaredConstructors:"+constructors);
        }

        //Gets the specified constructor
        System.out.println("====================================");
        Constructor constructor = c1.getConstructor(String.class,int.class,int.class);//Get public constructor
        System.out.println(constructor);
        constructor = c1.getDeclaredConstructor(String.class,int.class,int.class); //Get constructors with non-public attributes and constructors with public attributes
        System.out.println(constructor);

    }
}

Create an object for the runtime class

Role of class object

  • Create Class object: call newInstance() method of Class object
    1. Class must have a parameterless constructor
    2. The constructor of the class needs sufficient access rights
      PS: the operation can be instantiated only when the constructor in the class is explicitly called during the operation and the parameters are passed in
  • The steps are as follows:
    1. Get the constructor 4 of the specified parameter type of this Class through getdeclaraedconstructor (Class... parameterTypes) of Class class
    2. Pass an object array into the formal parameters of the constructor, which contains all the parameters required by the constructor
    3. Instantiate objects through Constructor

Call the specified method

  • Through reflection, the Method in the class is called and completed through the Method class
    1. Get a Method object through the getMethod(String name,Class... parameterTypes) Method of Class class, and set the parameter type required for this Method operation.
    2. Then use Object invoke(Object obj,Object[] args) to call and pass the parameter information of the obj object to be set to the method.
  • Object invoke(Object obj,Object[] args)
    1.Object corresponds to the return value of the original method. If the original method cannot return a value, null is returned
    2. If the original method is a static method, the formal parameter Object obj can be null
    3. If the original method parameter list is empty, Object[] args is null
    4. If the original method is declared as private, you need to display the setAccessible(true) method of the calling method object before calling this invoke() method to access the private method
//Dynamically create objects through reflection
public class Demo09 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //Get class object
        Class c1 = Class.forName("com.reflection.User");

        //Construct an object
        User user = (User) c1.newInstance(); //Essentially, a parameterless constructor is called
        System.out.println(user);

        //Creating objects through constructors
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user1 = (User) declaredConstructor.newInstance("Sugar sugar", 001, 18);
        System.out.println(user1);

        //Call normal methods through reflection
        Method setName = c1.getDeclaredMethod("setName", String.class);

        //invoke: activate (object, "value of method")
        setName.invoke(user,"Sugar sugar");
        System.out.println(user.getName());

        //Operation properties by reflection
        Field name = c1.getDeclaredField("name");
        //Private properties cannot be operated directly. We need to turn off the security detection of the program, and setAccessible(true) of properties and methods;
        name.setAccessible(true); //Turn off security detection
        name.set(user,"Sugar 2");
        System.out.println(user);
    }
}

  • setAccessible
    1. Method, Field and Constructor objects all have setAccessible() methods
    2. The switch that enables and disables access security checks when setAccessible is active
    3. If the parameter value is true, it means that the Java language access check is cancelled when the reflected object is used
      Improve the efficiency of reflection. If reflection must be used in the code, and the code of this sentence needs to be called frequently, please set it to true
      So that private members that cannot be accessed can also be accessed
    4. If the parameter value is false, it indicates that the reflected object should be checked for real-time java language access
//Analyze performance issues
public class Demo10 {
    //Normal mode call
    public static void test1(){
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Call in normal mode:"+(endTime-startTime));
    }
    //Reflection mode call
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
             getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Reflection mode call:"+(endTime-startTime));
    }
    //Reflection mode call off monitoring
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Reflection mode call off monitoring:"+(endTime-startTime));
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test1();
        test2();
        test3();
    }
}

Gets the complete structure of the runtime class

Reflection operation generics

  • java uses the generic erasure mechanism to introduce generics. Generics in java are only used by the compiler javac to ensure data security and avoid forced type conversion. However, once the compilation is completed, all types related to generics are erased
  • In order to manipulate these types through reflection, java adds ParameterizedType, GenericArrayType,TypeVariable and WildcardType to represent types that cannot be classified into Class but have the same name as the original type
  • ParameterizedType: represents a parameterized type, such as Collection
  • GenericArrayType: indicates that an element type is a parameterized type or an array type of type variable
  • TypeVariable: it is the common parent interface of various data type variables
  • WildcardType: represents a wildcard type expression
//Get generics through reflection
public class Demo11 {

    public void test01(Map<String,User> map, List<User> list){
        System.out.println("test01");
    }
    public Map<String,User> test02(){
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Demo11.class.getMethod("test01", Map.class, List.class);

        //Get input parameter type
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("##:"+genericParameterType);
            if(genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments =  ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println("&&:"+actualTypeArgument);
                }
            }
        }

        method = Demo11.class.getMethod("test02", null);
        //Get return value type
        Type genericReturnType = method.getGenericReturnType();
        System.out.println("Test02##:"+genericReturnType);
        if(genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments =  ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("Test02&&:"+actualTypeArgument);
            }
        }
    }

}

Calls the specified structure of the runtime class

  • ROM: object relationship mapping -- > object relationship mapping
    1. Correspondence between class and table structure
    2. Attribute and field correspondence
    3. Object and record correspondence
  • Requirements: use annotation and reflection to complete the mapping relationship between class and table structure
public class Demo12 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class  c1 = Student2.class;
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("annotation:"+annotation);

        }
        //Gets the Value of the annotated Value
        Table annotation = (Table)c1.getAnnotation(Table.class);
        String value=annotation.value();
        System.out.println(value);

        //Gets the annotation specified by the class
        Field f = c1.getDeclaredField("name");
        FieldA annotation1 = f.getAnnotation(FieldA.class);
        System.out.println(annotation1.columnName());
        System.out.println(annotation1.type());
        System.out.println(annotation1.length());

    }
}
@Table("Student list")
class Student2{
    @FieldA(columnName = "number",type = "int",length = 10)
    private int id;
    @FieldA(columnName = "Age",type = "int",length = 10)
    private int age;
    @FieldA(columnName = "name",type = "varchar",length = 5)
    private String name;

    public Student2() {
    }

    public Student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldA{
    String columnName();
    String type();
    int length();
}

Topics: Java JavaEE intellij-idea