zoukankan      html  css  js  c++  java
  • java中常见面试题整理

    1.Java有几种数据类型?分别是什么?
     Java有8种数据类型:

       字符类型:char(16位)

       布尔类型:boolean(true/false)

       数值类型:

           整数类型:byte(8位),short(16位),int(32位),long(64位)

          浮点数类型:float(32位,直接赋值必须在数字后加f/F),double(64位赋值在数字 后加d/D/不加)
      简单数据类型对应的封装类:
        boolean    byte    char             short    int           long    float     double   void
        Boolean    Byte    Character   Short    Integer   Long   Flolat   Double   Void
      Java有5中引用类型(对象类型):
        类,接口,数组,枚举,标注
       Jvm的内存空间
       堆空间:分配对象:new Student()
       栈空间:临时变量:Student stu
       代码区:类的定义,静态资源 Student.class

    2.String、StringBuilder、StringBuffer的区别?和各自应用场景?
       String str1=”hello”;

       String str2=”hello”;

       String str3=new String(“hello”);

       String str4=new String(“hello”);

       str1=str2?    true

       str2=str3?    false

       str3=str4?    false

       str4.equals(str1)?  True   //equals方法默认比较的是内存地址,String类重写了equals方法,比较内容是否一致

       String str=“hello”这种方式创建字符串的时候,jvm会首先检查字符串常量池中是否存在该字符串对象,如果已存在,那么就不会在字符串常量池中再创建了,直接返回给该字符串     在字符串常量池中内存地址。如果该字符串还不存在该常量池中。那么就会在字符串常量池中先创建该字符串的对象,然后返回。 new String(“hello”)这种方式创建字符串对象的

       时候,首先会检查字符串常量池中是否存在该字符串对象,如果已存在,那么就不会在字符串常量池中再创建了,如果还没存在,那么就会在字符串常量池中创建“hello”字符串对     象,然后还会到对内存中再创建一份字符串的对象,把字符串常量池中的“hello”字符串拷贝到内存中的字符串对象,然后返回堆内存中字符串对象的内存地址

       笔试题:new String(“abc”);创建了几个对象?答:两个对象,一个对象位于字符串常量池中,一个位于堆内存中

             使用字节数组或字符数组都可以构建一个字符串对象如

             byte[] buf={97,98,99};

             str= new String(buf); //输出abc char[] arr={‘明’,‘天’};

             str= new String(arr); //输出明天

            字符串特点:字符串值是常量,它的值在创建后不能修改,字符串的内容一旦发生改变,那么马上会创建一个新的对象。

           注意:字符串的内容不适宜频繁修改,因为一旦修改马上创建一个新的对象,如果需要频繁修改字符串的内容,建议使用字符串缓冲类(StringBuffer) StringBuffer实际上是一         个存储字符的容器,StringBuffer底层是依赖了一个字符数组才能存储数据的,该字符数组默认的初始容量长度是16,如果初始容量的长度不够,则自动增加1倍

       StringBuffer与StringBuilder的相同点与不同点:

       相同点:

       1. 两个类都是字符串缓冲类

       2. 两个类的方法都是一致的

       不同点:

       1. StringBuffer是线程安全的,操作效率低;StringBuilder是线程非安全的,操作效率 高

       2. StringBuffer是jdk1.0出现的,StringBuilder是jdk1.5出现的 推荐使用StringBuilder,因为操作效率高

    3.Object类下有哪些方法?

        Object clone() 创建并返回此对象的一个副本

        boolean equals(Object obj)指示其他某个对象是否与此对象相等

        protected void finalize()垃圾回收器确定不存在对该对象的更多引用时。有对象的垃圾回收器调用此方法

        Class<?> getClass()返回此Object的运行时类

        int hashCode()返回该对象的哈希吗值

        void notify()唤醒在此对象监视器上等待的单个线程

        void notifyAll()唤醒在此对象监视器上等待的所有线程

        String toString()返回该对象的字符串表示

        void wait()在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待

        void wait(long timeout)在其他线程调用此对象的notify()或notifyAll()方法,或者 超过制定的时间前,导致当前线程等待

        void wait(long timeout,int nanos)在其他线程调用此对象的notify()或notifyAll() 方法,或者其他某个线程中断当前线程,后者已超出某个实际时间量前,导致当前线程等待。

       补充问题:wait和sleep的区别是什么?
       1)wait和notify在线程问题中实组合使用的
       2)wait方法执行前会释放锁,而sleep不会

    4.面向对象的特点有哪些?重写和重载的区别是什么?
     面向对象的特地点:继承、封装、多态
     函数的重写:在继承中,子类可以定义和父类相同名称且参数列表一致的函数,将这种函数称之为函数的重写。当子类调用该函数,一定是调用重写后的函数,可以通过super关键字进行父类的重写函数的调用

       注意:

    1.    函数名必须相同
    2.    参数列表必须相同
    3.    子类重写父类的函数的时候,函数的访问权限必须大于父类的函数的访问权限
    4.    子类重写父类的函数的时候,返回值的类型必须是父类函数类型或返回值类型的子类。不能返回比父类更大的数据类型;


       函数的重载:

       在同一个类中,有一个以上的同名函数,只要函数的参数列表或参数类型不一样即可,与返回值无关。函数重载存在的原因:为了增强方法的阅读性,优化了程序设计。

    5.接口和抽象类有什么区别?
        抽象类的特点:

    1.  有抽象函数的类一定是抽象类
    2.   抽象类中不一定有抽象函数
    3.  抽象类不能创建对象
    4.  抽象类主要为了提高代码的复用性,让子类继承去使用
    5.  编译器强制子类实现抽象类父类的未实现的方法(可以不实现,前提是子类也要声明为抽象的)
    6.  抽象类一定有构造函数。主要是为了初始化抽象类中的属性,通常由子类实现
    7.  抽象类可以继承普通类和抽象类
    8.  final与abstract不能共存
    9.  static与abstract不能共存
    10.  private不能修饰抽象类


       接口的特点:

    1.    类实现接口可以通过implements实现,实现接口的时候必须把接口中的所有方法实现,一个类可以实现多个接口
    2.    接口定义的所有的属性默认是public static final的,即静态常量既然是常量,那么定义的时候必须赋值
    3.    接口中定义的方法不能有方法体,接口中定义的方法默认添加public abstract
    4.    有抽象函数的不一定是抽象类,也可以是接口类
    5.    由于接口中的方法默认是抽象的,所以不能实例化
    6.    对于接口而言,可以使用子类来实现接口中未被实现的功能函数
    7.    如果实现类中要访问接口中的成员,不能使用super关键字,因为两者之间没有显示的继承关系,况且接口中的成员属性是静态的,可以使用接口名直接访问
    8.    接口没有构造方法
    9.    一个类可以实现多个接口,只能继承一个类。一个接口可继承多个接口


    6.ArrayList和LinkedList的实现原理是什么?各有什么优缺点?
       ArrayList底层采用数组实现,默认10,每次增长60%,查询块,增删慢
       LinkList底层采用链表实现,增删块,查询慢

    ---|Collection: 单列集合

          ---|List: 有存储顺序, 可重复

                  ---|ArrayList:   数组实现, 查找快, 增删慢    由于是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快                           

           ---|LinkedList:  链表实现, 增删快, 查找慢   由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高但查询时需要一个一个的遍历, 所以效率较低             

                  ---|Vector:   和ArrayList原理相同, 但线程安全, 效率略低   和ArrayList实现方式相同, 但考虑了线程安全问题, 所以效率略

           ---|Set: 无存储顺序, 不可重复

                  ---|HashSet

                  ---|TreeSet

                  ---|LinkedHashSet

    ---| Map: 键值对

           ---|HashMap

           ---|TreeMap

           ---|HashTable

           ---|LinkedHashMap

       什么时候该使用什么样的集合
              Collection 我们需要保存若干个对象的时候使用集合。
              List   如果我们需要保留存储顺序, 并且保留重复元素, 使用List.如果查询较多, 那么使用ArrayList如果存取较多, 那么使用LinkedList如果需要线程安全, 那么使用Vector
              Set  如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set.如果我们需要将元素排序, 那么使用TreeSet如果我们不需要排序, 使用HashSet, HashSet比TreeSet效率高.如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet

    7.HashMap 的数据结构,如何解决hash冲突问题?何时发生reHash操作?reHash过程是怎么样的?
    HashMap的数据结构是数组+链表的形式,底层采用的是数组,数组中每一项采用的是链表。
    若发生hash冲突问题,即在同一hash位置有一个以上元素,此时元素应以链表的方式依次往后排放,以此来解决hash冲突问题。

    当数组中元素大于hashMap的极限容量(容量*负载因子,负载因子默认为0.75,初始容量默认为16),此时会发生rehash操作。
    rehash操作的过程是开辟一个新的数组空间,然后将所有元素重新使用hash算法
    解决hash冲突问题的方法是扩容,当数组中元素大于hashMap点的极限容量(容量*负载因子),负载因子默认为0.75,初始容量默认为16,此时会发生rehash操作。
    rehash操作的方式是开辟一个新的数组空间,然后将所有元素进行重新使用hash算法算出位置后以新的排序方式放在新的数组中。

    8.hashMap是线程安全的吗?hashMap和hashTable的区别是什么?

    1. hashMap是线程不安全的,而hashTable是线程安全的
    2. hashMap是不同步的,而hashTable是同步的
    3. hashMap的效率比hashTable高
    4. hashMap允许NULL键和NULL值,hashTable不允许
    5. 扩容方式不一样:hashMap:原始容量=16, 扩容后:2*原始容量
                    hashTable:原始容量=11, 扩容后:2*原始容量+1

    9.ConcurrentHanshMap的特点是什么?它比hashTable效率高的原因是什么?
    ConcurrentHanshMap的特点是:它的同步机制是基于lock操作的,保证同步的时候,锁住的不是整个对象,而是某一个segment;
    hashtable是基于sychonized操作的,锁住的是整个对象,所以效率低。

    10.volatile关键字的作用是什么?
    volatile可以保证可见性和有序性。

    volatile被设计用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它都是直接从内存当中取,而不会利用缓存。在使用了volatile修饰成员变量后,所有线程在任何时候所看到的变量的值都是相同的。保证了可见性。但是volatile会阻止编译器对代码的优化,降低程序的执行效率,所以,除非迫不得已,尽量不使用volatile。

    11.static关键字的作用是什么?
           static关键字的作用主要是为了实现对象之间重复属性的数据共享
           static的使用:
           主要用于修饰类的成员
              成员变量:①非静态成员变量:需要通过创建对象来访问
                        ②静态成员变量:使用类名直接调用,也可以通过对象访问
              成员方法:①静态函数中不能访问非静态成员变量,只能访问静态变量
                        ②静态方法不可以定义this,super关键字

              ③非静态函数:非静态函数中可以访问静态成员变量

    12.final关键字的作用是什么
           final关键字主要用于修饰类、类成员、方法、以及方法的形参
      ①final修饰成员属性,说明该成员属性是常量,不能被修改。(常量名必须大写)
      ②基本数据类型,final使其值不变;对象引用:final使其引用恒定不变,无法让其
          指向一个新的对象,但是对象自身却可以被修改;该关键字一般和static组合使用
             (常量可优先加载,不必等到创建对象的时候再初始化);final和static可互换位
               置;常量一般final修饰
      ③final修饰类:该类是最终类,不能被继承
      ④final修饰方法:该方法是最终方法,不能被重写(如果一个类中的函数都被修饰为final时,可以将类定义为final)

    13.synchronized关键字的作用是什么?synchronized有几种用法?
      synchronized是给同步代码块或同步函数加锁,有两种用法:
      方式1:同步代码块:
      Synchronized(“锁对象”){
        需要同步的代码块
      }
      方式2:同步函数:
      函数使用synchronized修饰

    14.synchronized和lock的区别
      1)synchronized在成功完成功能或者抛出异常时,虚拟机会自动释放线程占有的锁; 而Lock对象在发生异常时,如果没有主动调用unLock()方法去释放锁,则锁对象会一直持有,因此使用Lock时需要在finally块中释放锁;

      2)lock接口锁可以通过多种方法来尝试获取锁包括立即返回是否成功的tryLock(),以及一直尝试获取的lock()方法和尝试等待指定时间长度获取的方法,比synchronized相对灵活了许多

      3)通过在读多,写少的高并发情况下,我们用ReentrantRead,WriteLock分别获取读锁和写锁来提高系统的性能,因为读锁是共享锁,即可以同时有多个线程读取共享资源,而写锁则保证了对共享资源的修改只能是单线程的。

           补充:
      关于线程:
      1.一个java应用程序至少有两个线程,一个是主线程,负责main方法代码的执行,一个是垃圾回收器线程,负责回收垃圾
      2.多线程的好处:①解决了一个进程能同时执行多个任务的问题②提高了资源利用率
      3.多线程弊端:①增加CPU的负担②降低了一个进程中线程的执行概率③引发了线程安全问题④出现了死锁现象
      4.创建线程的方式有2种
        方式一:①自定义一个类继承Thread类②重写Thread的run()方法,自定义线程就写在run()方法中③创建Thread的子类对象,并且调用start方法开启线程
        方式二:①自定义一个类实现Runable接口②实现Runable的run方法,把自定义线程的任务定义在run方法上③创建Runable实现类对象④创建Thread类的对象,并且把

            Runable实现类的对象作为实参传递⑤调用Thread类的start方法开启线程

        推荐使用第二种,原因:因为java是单继承多实现的
      5.出现线程安全问题的根本原因:①存在两个或两个以上线程对象,且线程之间共享了同一资源②有多个语句操作者同一资源
      6.线程安全问题的解决方式:java线程同步机制:
      方式1:同步代码块:
      Synchronized(“锁对象”){
        需要同步的代码块
      }
      同步代码块要注意的事项:
      ①任意一个对象都可以作为锁对象
      ②在同步代码块中调用了sleep方法不释放锁对象
      ③只有真正存在线程安全问题的时候才使用同步代码块,否则会降低相率
      ④多线程操作的锁对象必须是唯一共享的。否则无效
      方式二:同步函数:
      函数使用synchronized修饰
      注意:
      ①如果是一个非静态的同步函数的锁对象是this对象,如果是静态的同步函数的锁对象是当前函数所属类的字节码文件(class对象)
      ②同步函数的锁对象是固定的,不能由你来指定

      推荐使用同步代码块
      ①同步代码块的锁对象可以由我们随意指定,同步函数不行
      ②同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数的代码块被同步了

    15.死锁现象:
      死锁现象出现的根本原因:

    1. 出现两个或两个以上的线程
    2. 出现两个或两个以上的共享资源

    死锁现象的解决方案:没有方案,只能尽量避免

    16.wait与notify方法要注意的事项:

    1. wait方法与notify方法是属于Object对象的,因为任意对象都可作为锁对象
    2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能使用
    3. wait方法与notify方法必须要由锁对象调用


    17.线程的停止:

    1. 停止一个线程,我们一般都会通过一个变量去控制
    2. 如果需要停止一个等待状态下的线程,我们需要通过变量配合niotify()和interrupt()来使用

    18.守护线程(后台线程):在一个进程中,如果只剩下守护线程,那么守护线程也会死亡。

    1. 一个线程默认都不是守护线程,使用d.setDaemon(true),设置是否为守护线程,true为是,false为非守护线程
    2. 一个线程如果执行join()语句,那么就有新的线程加入,执行该语句的线程必须要让步给新的线程完成任务,然后才能执行

    19.MQ原理:
      消息队列,工作方式是不同步的

    20.hashMap与ConcurrentHashMap的区别
      HashMap---hashTable
          首先hashMap的是线程不安全的,但是效率比较高,而hashTable是线程安全的,但效率有很低,若要在保证线程安全的前提下有较高的效率,可考虑使用

          concurrentHashMap。
      HashTable—ConCurrentHashMap
          concurrentHashMap和HashTable一样都是有加了锁操作的,都是线程安全的,然而它们的锁机制不一样,所以concurrentHashMap比HashTable的效率高。

               concurrentHashMap是基于lock机制的,有16把锁分别锁住concurrentHashMap的16的部分,而HashTable锁住的是整个HashTable对象。

    21.Java注解的原理、作用是什么?

      原理:从java源码到class字节码是由编译器完成的,编译器会对java源码进行解析并生成class文件,而注解也是在编译时由编译器进行处理,编译器会对注解符号处理并附加到class结构中,根据jvm规范,class文件结构是严格有序的格式,唯一可以附加信息到class结构中的方式就是保存到class结构的attributes属性中。我们知道对于类、字段、方法,在class结构中都有自己特定的表结构,而且各自都有自己的属性,而对于注解,作用的范围也可以不同,可以作用在类上,也可以作用在字段或方法上,这时编译器会对应将注解信息存放到类、字段、方法自己的属性上。在我们的AnnotationTest类被编译后,在对应的AnnotationTest.class文件中会包含一个

    RuntimeVisibleAnnotations属性,由于这个注解是作用在类上,所以此属性被添加到类的属性集上。即Test注解的键值对value=test会被记录起来。而当JVM加载

    AnnotationTest.class文件字节码时,就会将RuntimeVisibleAnnotations属性值保存到AnnotationTest的Class对象中,于是就可以通过

    AnnotationTest.class.getAnnotation(Test.class)获取到Test注解对象,进而再通过Test注解对象获取到Test里面的属性值。这里可能会有疑问,Test注解对象是什么?其实

    注解被编译后的本质就是一个继承Annotation接口的接口,所以@Test其实就是“public interface Test extends Annotation”,当我们通过

    AnnotationTest.class.getAnnotation(Test.class)调用时,JDK会通过动态代理生成一个实现了Test接口的对象,并把将RuntimeVisibleAnnotations属性值设置进此对象中,    此对象即为Test注解对象,通过它的value()方法就可以获取到注解值。Java注解实现机制的整个过程如上面所示,它的实现需要编译器和JVM一起配合

    作用:·      

      1)生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等· 

      2)跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基 于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配 置文件的数量。

      3)在编译时进行格式检查。如@Override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

    22.Java反射机制是什么?通过反射可以做什么?Class类下主要的方法有哪些
      类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。 通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。
    Class类的方法有:
    1)获取class类的三种方式:
    ①Class.forName();
    // 方式一
    Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    ②类名.class
    // 方式二
    Class clazz2 = Person.class;
    ③对象名.getClass();
    // 方式三
    Person p1 = new Person();
    Class clazz3 = p1.getClass();
    2)通过class类获取类型的一些信息
    Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    ①getName()类的名称(全名,全限定名)
    // 获取类的名称
    String name = clazz1.getName();
    ②getSimpleName()类的的简单名称(不带包名)
    // 获取类的简单名称
    System.out.println(clazz1.getSimpleName());
    ③getModifiers(); 类的的修饰符
    // 获取类的修饰符
    int modifiers = clazz1.getModifiers();
    ④创建对象
    无参数构造创建对象
    newInstance()
    // 构建对象(默认调用无参数构造.)
    Object ins = clazz1.newInstance();
    Person p = (Person) ins;
    ⑤获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例
    Constructor<T> getConstructor(Class<?>... parameterTypes)
    // 获取指定参数的构造函数
    Constructor<?> con = clazz1.getConstructor(String.class, int.class);
    // 使用Constructor创建对象.
    Object p1 = con.newInstance("jack", 28);
    System.out.println(((Person) p1).getName());
    3)通过class类获取类型中方法的信息
    Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    ①获取公共方法包括继承的父类的方法
    getMethods()返回一个数组,元素类型是Method
    // 1.获取非私用方法(包括父类继承的方法)
    Method[] methods = clazz1.getMethods();
    System.out.println(methods.length);
    for (Method m : methods) {
    // System.out.println(m.getName());
    if ("eat".equals(m.getName())) {
    m.invoke(clazz1.newInstance(), null);
    ②获取指定参数的公共方法
    getMethod("setName", String.class);
    ③获得所有的方法,包括私有
    Method[] getDeclaredMethods()
    ④获得指定参数的方法,包括私有
    Method getDeclaredMethod(String name, Class<?>... parameterTypes)

      /**    * 获取公有方法.    * @throws Exception    * */  
    
    private static void test3() throws Exception {
    
          Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person"); 
    
         // 1.获取非私用方法(包括父类继承的方法)
    
          Method[] methods = clazz1.getMethods(); 
    
         System.out.println(methods.length); 
    
         for (Method m : methods) {
    
             // System.out.println(m.getName()); 
    
            if ("eat".equals(m.getName())) { 
    
               m.invoke(clazz1.newInstance(), null); 
    
            } 
    
         }
    
       }
    
    /**    * 获取指定方法签名的方法    *    * @throws Exception    * */  
    
    private static void test4() throws Exception {
    
          Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    
          // 获取指定名称的函数
    
          Method method1 = clazz1.getMethod("eat", null);
    
          method1.invoke(new Person(), null);   }
    
    /**    * 获取指定方法名且有参数的方法    *    * @throws Exception    * */ 
    
      private static void test5() throws Exception { 
    
         Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person"); 
    
         Method method = clazz1.getMethod("eat", String.class);
    
         method.invoke(new Person(), "包子");
    
       }
    
        /**    * 获取指定方法名,参数列表为空的方法.    *    * @throws Exception    * */ 
    
      private static void test4() throws Exception {
    
          Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    
          // 获取指定名称的函数
    
          Method method1 = clazz1.getMethod("eat", null); 
    
         method1.invoke(new Person(), null);   }
    
    
    /**    * 反射静态方法    * @throws Exception    * */
    
       private static void test7() throws Exception {
    
          Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    
          Method method = clazz1.getMethod("play", null);
    
          method.invoke(null, null);
    
       } 
    
       /**    * 访问私有方法 暴力反射    * @throws Exception    * */
    
       private static void test6() throws Exception {
    
          Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    
          Method method = clazz1.getDeclaredMethod("movie", String.class);
    
          method.setAccessible(true);
    
         method.invoke(new Person(), "小明");
    
       } 

    4)通过Class类获取类型中的字段的信息
    ①获取公共字段
    Field[] getFields()
    ②获取指定参数的公共字段
    Field getField(String name)
    ③获取所有的字段
    Field[] getDeclaredFields()
    ④获取指定参数的字段,包括私用
    Field getDeclaredField(String name)

    23.MySQL增删改查的基本命令是什么?熟记

    http://www.cnblogs.com/mercuryji/p/mysql_operate.html
    24.SPring中@Autowried、@Resource、@Component、@Service、@Controller、@PostConstruct注解的含义、作用是什么?
    @Component 指定把一个对象加入IOC容器
    @Repository 作用同@Component; 在持久层使用
    @Service 作用同@Component; 在业务逻辑层使用
    @Controller 作用同@Component; 在控制层使用,用于指示Spring类的实例是一个控制器
    @Resource 属性注入(多例时,要确保同一类型只有同一变量)是J2EE自带的注解,可以按name和type匹配,默认按类型匹配
    @Autowried 属性注入,默认按名臣匹配
    @postConstruct 被该注解修饰的方法会在服务器加载servlet的时候运行,并且只会被服务器调用一次,类似于servlet的init()方法。被@PostContruct修饰的方法会在构造函数只会,init()之前运行。

  • 相关阅读:
    第九周作业
    第八周作业
    第七周作业
    作业2
    作业1
    2019春总结作业
    第十四周总结
    十二周编程总结
    十一周编程总结
    第十周作业
  • 原文地址:https://www.cnblogs.com/mercuryji/p/java.html
Copyright © 2011-2022 走看看