中级java工程师面试题

1.string类的常用方法有哪些?

答:https://zhidao.baidu.com/question/232452768.html

2.String,StringBuffer,StringBuilder的区别。

答:1)如果操作少量的数据用String(查看源码得知,String类的声明是:public final,改变它的值相当于创建一个新的字符串)

       2)单线程下操作大量的数据用StringBuilder

        3)多线程下操作大量的数据用StringBuffer

https://www.cnblogs.com/A_ming/archive/2010/04/13/1711395.html

3,String str = new String("xyz");创建了几个对象。

答:两个

延伸: 

String s1="a";
String s2="a";
System.out.print(s1==s2);

输出是True

因为:原因是Java为了避免产生大量的String对象,设计了一个字符串常量池。工作原理是这样的,创建一个字符串时,JVM首先为检查字符串常量池中是否有值相等的字符串,如果有,则不再创建,直接返回该字符串的引用地址,若没有,则创建,然后放到字符串常量池中,并返回新创建的字符串的引用地址。

4,说几个你常见到的异常。

答:

空指针异常:NullPointerException

  数组下表越界异常:ArrayIndexOutOfBoundsException

内存不足错误:java.lang.OutOfMemoryError

字符串转换为数字异常:NumberFormatException

5,hashtable和hashmap的区别是什么?

答;

    1)、继承的父类不同

      Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。

      2)、线程安全性不同

      javadoc中关于hashmap的一段描述如下:此实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步

      Hashtable 中的方法是Synchronize的

 3)、是否提供contains方法

      HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。

      Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。

  4)、key和value是否允许null值

      Hashtable中,key和value都不允许出现null值。但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

 5)、两个遍历方式的内部实现上不同

      Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 

   6)、hash值不同

(另一种解释:

  1. Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
  • 2,HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸:
static int hash(int h) {
     h ^= (h >>> 20) ^ (h >>> 12);
     return h ^ (h >>> 7) ^ (h >>> 4);
 }

static int indexFor(int h, int length) {
     return h & (length-1);
 }

      哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

      hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。

      Hashtable计算hash值,直接用key的hashCode(),而HashMap重新计算了key的hash值,Hashtable在求hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用hash&0x7FFFFFFF后,再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值有可能为负数,而&0x7FFFFFFF后,只有符号外改变,而后面的位都不变。

      7)、内部实现使用的数组初始化和扩容方式不同

      HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
      Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

      Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。

https://blog.csdn.net/fujiakai/article/details/51585767

6.hashmap的底层实现方式是什么?

HashMap的底层通过位桶实现,位桶里面存的是链表(1.7以前)或者红黑树(有序,1.8开始) ,其实就是数组加链表(或者红黑树)的格式,通过判断hashCode定位位桶中的下标,通过equals定位目标值在链表中的位置,所以如果你使用的key使用可变类(非final修饰的类),那么你在自定义hashCode和equals的时候一定要注意要满足:如果两个对象equals那么一定要hashCode相同,如果是hashCode相同的话不一定要求equals!所以一般来说不要自定义hashCode和equls,推荐使用不可变类对象做key,比如Integer、String等等。

7.Vector 和 ArrayList 的区别?

这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,,并且其中的数据是允许重复的,这是HashSet之类的集合的最大不同处,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素(本来题目问的与hashset没有任何关系,但为了说清楚ArrayList与Vector的功能,我们使用对比方式,更有利于说明问题)。

ArrayList与Vector的区别,这主要包括两个方面:. (1)同步性:

Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。

备注:对于Vector&ArrayList、Hashtable&HashMap,要记住线程安全的问题,记住Vector与Hashtable是旧的,是java一诞生就提供了的,它们是线程安全的,ArrayList与HashMap是java2时才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。(2)数据增长:

ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。

8.怎么遍历一个map?写一下。

1

for(String key : map.keySet()){
    System.out.println(key+" "+map.get(key)+"");
}

2

while(iterator.hasNext()){
    Map.Entry<String,String> entry=iterator.next();
    System.out.println(entry.getKey()+" "+entry.getValue()+"");
}

3:推荐,尤其是容量大时

for(Map.Entry<String,String> entry :map.entrySet()){
    System.out.println(entry.getKey()+" "+entry.getValue()+"");
}

4:只遍历值

for(String v:map.values()){
    System.out.println(v+"");
}

9.说一下list,set,map的区别。

List:1.可以允许重复的对象。

    2.可以插入多个null元素。

        3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。

        4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

 Set:1.不允许重复对象

     2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。

        3. 只允许一个 null 元素

        4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

Map:1.Map不是collection的子接口或者实现类。Map是一个接口。

           2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。

           3. TreeMap 也通过 Comparator  或者 Comparable 维护了一个排序顺序。

           4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。

        5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

延伸:

2.面试题:什么场景下使用list,set,map呢?

(或者会问为什么这里要用list、或者set、map,这里回答它们的优缺点就可以了)

答:

  1. 如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。

  2. 如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。

  3. 如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。

  4. 如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。

https://www.cnblogs.com/IvesHe/p/6108933.html

10.你的项目中用的是多线程还是单线程?

11.多线程会遇到那些问题?怎么解决死锁?

Java程序基本都要涉及到多线程,而在多线程环境中不可避免的要遇到线程死锁的问题。Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能性来解决。

产生死锁可能性的最根本原因是:线程在获得一个锁L1的情况下再去申请另外一个锁L2,也就是锁L1想要包含了锁L2,也就是说在获得了锁L1,并且没有释放锁L1的情况下,又去申请获得锁L2,这个是产生死锁的最根本原因。另一个原因是默认的锁申请操作是阻塞的

避免死锁的方法:

1,尽量减少同步范围,即synchronized如果能只包围一个对象,就不要包围这个对象所在方法

2,申请锁的减少交叉,按顺序申请

3,死锁一般是会有一个死锁环,添加睡眠可以减少死锁环的概率

12.用java写一个多线程程序,如写四个线程,二个加1,二个对一变量减一,输出:

package Other;

public class StudyThread {

    int j = 1;
    public synchronized void inc() {
        j++;
        System.out.println(Thread.currentThread().getName() + "-inc:" + j);
    }
    public synchronized void dec() {
        j--;
        System.out.println(Thread.currentThread().getName() + "-inc:" + j);
    }

    class Tinc implements Runnable {
        public void run() {
            inc();
        }
    }

    class Tdec implements Runnable {
        public void run() {
            dec();
        }
    }
    public static void main(String args[]) {
        StudyThread studyThread = new StudyThread();
        Tinc t1 = studyThread.new Tinc();
        Tdec t11=studyThread.new Tdec();
        for(int i=0;i<2;i++){
            Thread thread=new Thread(t1);
            thread.start();
            Thread thread1=new Thread(t11);
            thread1.start();
        }
    }
}

13.至少说六点interface和abstract的区别。

 1.相同点 
A. 两者都是抽象类,都不能实例化。 
B. interface实现类及abstrctclass的子类都必须要实现已经声明的抽象方法。

2. 不同点 

A. interface需要实现,要用implements,而abstract class需要继承,要用extends。 
B. 一个类可以实现多个interface,但一个类只能继承一个abstract class。 
C. interface强调特定功能的实现,而abstractclass强调所属关系。 
D. 尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。interface中的每一个方法都是抽象方法,都只是声明的(declaration,没有方法体),实现类必须要实现。而abstractclass的子类可以有选择地实现。 

E. abstract class是interface与Class的中介。 
interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也不能声明实例变量。然而,interface却可以声明常量变量,并且在JDK中不难找出这种例子。但将常量变量放在interface中违背了其作为接口的作用而存在的宗旨,也混淆了interface与类的不同价值。如果的确需要,可以将其放在相应的abstractclass或Class中。 
abstract class在interface及Class中起到了承上启下的作用。一方面,abstract class是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可以定义自己的实例变量,以供子类通过继承来使用。

    一是Abastract class中并非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,子类必须实现。那些没有abstract的方法,在Abstrct class中必须定义方法体。 
    二是abstract class的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象的方式,无需实现,留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。 

1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。

    2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
    3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
    4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
    5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
    6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
    7.接口中的方法默认都是 public abstract 类型的。

14.怎么把数组放到对象里面?

问题比较模糊

15.给你一组字符串如:7i8hy4jjnb2.让你编程输出里面的数字:7842.

for (int i = 0; i < str.length(); i++) {
    if (Character.isDigit(str.charAt(i))) {
        char c = str.charAt(i);
        System.out.print(c);
    }
}

或:

String str1 = str.replaceAll("[a-z]", "");

16.多线程有几种实现方式?都是什么?同步有几种实现方式?都是什么?

Java多线程实现的三种方式:

1,继承Thread类创建线程类:重写父类run( )方法

public class thread1 extends Thread {
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println("线程一"+i);
        }
    }

    public static void main(String[] args) {
        thread1 th1 = new thread1();
        thread1 th2 = new thread1();
        th1.run();
        th2.run();
    }
}

 run( )方法只是普通的方法,是顺序执行的,虽然我们是写了一个线程,但是并没有体现出多线程的意义。为了体现多线程,应该使用start( )方法来启动线程,start()方法会自动调用run( )方法。所以上面的代码改为:

public class thread1 extends Thread {
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println("线程一"+i);
        }
    }
    public static void main(String[] args) {
        thread1 th1 = new thread1();
        thread1 th2 = new thread1();
        th1.start();
        th2.start();
    }
}
通过start( )方法启动的线程。不管th1.start( )调用的run( )方法是否执行完,都继续执行th2.start( )。如果下面有别的代码也同样不需要等待th2.start( )执行完而继续执行。

2,实现Runnable接口创建线程类

public class thread2 implements Runnable {
    public String ThreadName;

    public thread2(String tName){
        ThreadName = tName;
    }

    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println(ThreadName);
        }
    }
    public static void main(String[] args) {
        thread2 th1 = new thread2("线程A");
        thread2 th2 = new thread2("线程B");
        Thread myth1 = new Thread(th1);
        Thread myth2 = new Thread(th2);
        myth1.start();
        myth2.start();
    }
}

   其实Thread类也是实现了Runnable接口,代表了一个线程的实例,并且启动线程唯一的方法就是通过Thread类的start( )方法。所以第二种实现多线程的方法必须要提拔个工艺new一个Thread类去启动线程。同样的,也不能只是运行run( )方法,因为这样只是一个线程。

3,使用ExecutorService、Callable、Future实现由返回结果的多线程

 这种方式是之前没有尝试过的,ExecutorService是一个线程池接口,可返回值的任务必须实现Callable接口,无返回值得任务必须实现Runnable接口。执行Callable任务后,可以获取一个Future对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合ExecutorService接口就可以实现有返回结果的多线程了

/**
 * 有返回值的线程 
 */
@SuppressWarnings("unchecked")
class Test {
    public static void main(String[] args) throws ExecutionException,
            InterruptedException {
        System.out.println("----程序开始运行----");
        Date date1 = new Date();

        int taskSize = 5;
        // 创建一个线程池  
        ExecutorService pool = Executors.newFixedThreadPool(taskSize);
        // 创建多个有返回值的任务  
        List<Future> list = new ArrayList<Future>();
        for (int i = 0; i < taskSize; i++) {
            Callable c = new MyCallable(i + " ");
            // 执行任务并获取Future对象  
            Future f = pool.submit(c);
            // System.out.println(">>>" + f.get().toString());  
            list.add(f);
        }
        // 关闭线程池  
        pool.shutdown();

        // 获取所有并发任务的运行结果  
        for (Future f : list) {
            // 从Future对象上获取任务的返回值,并输出到控制台  
            System.out.println(">>>" + f.get().toString());
        }

        Date date2 = new Date();
        System.out.println("----程序结束运行----,程序运行时间【"
                + (date2.getTime() - date1.getTime()) + "毫秒】");
    }
}

class MyCallable implements Callable<Object> {
    private String taskNum;

    MyCallable(String taskNum) {
        this.taskNum = taskNum;
    }

    public Object call() throws Exception {
        System.out.println(">>>" + taskNum + "任务启动");
        Date dateTmp1 = new Date();
        Thread.sleep(1000);
        Date dateTmp2 = new Date();
        long time = dateTmp2.getTime() - dateTmp1.getTime();
        System.out.println(">>>" + taskNum + "任务终止");
        return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
    }
}

同步的实现方法有五种:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步

其中多线程实现过程中需注意重写或者覆盖run()方法,而对于同步的实现方法中使用较常使用的是利用synchronized编写同步方法和代码块。

 17.java类实现序列化有几种实现方式?都是什么?(二种)不熟悉

Java对象的序列化有两种方式。

a.是相应的对象实现了序列化接口Serializable,这个使用的比较多,对于序列化接口Serializable接口是一个空的接口,它的主要作用就是 标识这个对象时可序列化的,jre对象在传输对象的时候会进行相关的封装。这里就不做过多的介绍了。

b.实现序列化的第二种方式为实现接口Externalizable

1,首先,我们在序列化对象的时候,由于这个类实现了Externalizable 接口,在writeExternal()方法里定义了哪些属性可以序列化,

2.也是最应该注意的,如果你先序列化对象A后序列化B,那么在反序列化的时候一定记着JAVA规定先读到的对象 是先被序列化的对象,不要先接收对象B,那样会报错.尤其在使用上面的Externalizable的时候一定要注意读取 的先后顺序。 3.实现序列化接口的对象并不强制声明唯一的serialVersionUID,是否声明serialVersionUID对于对象序列化的向 上向下的兼容性有很大的影响。,

https://blog.csdn.net/u012554102/article/details/51902697

18.java开发中“==” 和 “equals” 有何区别?

==判断的是两个字符串地址是否相同
.equals才是比较字符串内容

19.static局部变量与全局变量的区别,编译后映射文件是否包含此类变量的地址。

改问题:static全局变量与普通的全局变量有什么区别?

             static局部变量和普通局部变量有什么区别?

              static函数与普通函数有什么区别?   

1) 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。 

2) 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。

     把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

3) static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件 

https://blog.csdn.net/u012497906/article/details/48522715

https://www.cnblogs.com/michaelShao/p/6698504.html

20.在日常工作中,使用过哪些 java core 包,遇到java core 的那些异常?(可以写中文)

JAVA分为J2SE, J2EE ,J2ME三个版本

其中J2SE包括Core JAVA和Desktop JAVA
Core JA搜索VA主要是JAVA语言方面的内容
Desktop JAVA主要是JAVA的桌面应用方面的内容

21.在servlet中怎么获取页面传过来的 name="a" 或者 id="b" 的<input>输入框的值?

在servlet中获取请求中的表单值,是通过request.getParameter("参数时input标签的name");
在jsp页面上获取一个input标签的值,那就用document.getElementById().value;或者document.getElementsByName().value;

22.jsp和servlet有哪些相同点和不同点,他们之间的联系是什么?为什么要用jsp做显示而不用servlet?

jsp及Servlet经典面试题以及答案:这个问题更全

https://blog.csdn.net/u013842976/article/details/52275344

插入:session与cookie的差别

1,session 在服务器端,cookie 在客户端(浏览器)
2,session 默认被存在在服务器的一个文件里(不是内存)
3,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
4,session 可以放在 文件、数据库、或内存中都可以。
5,用户验证这种场合一般会用 session

因此,维持一个会话的核心就是客户端的唯一标识,即 session id

23.说一下servlet的生命周期,在执行servlet的过程中分别执行了哪些方法?每个方法具体负责什么?可以实现一些什么内容?

https://blog.csdn.net/javaloveiphone/article/details/8154791

24,你知道easyUI吗?

jQuery EasyUI是一组基于jQuery的UI插件集合体,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面。开发者不需要编写复杂的javascript,也不需要对css样式有深入的了解,开发者需要了解的只有一些简单的html标签。

https://baike.baidu.com/item/jQueryEasyUI/1733327?fr=aladdin

25.<div><span>1</span><span>2</span><span>3</span></div>如何获取第二个span的值?

简单

26.用js或者jquery获取页面上name="a" 或者 id="b" <input>输入框的值.

https://blog.csdn.net/zzy442054/article/details/68957985未完

猜你喜欢

转载自my.oschina.net/u/3796880/blog/1793456