2020Android初中级面试知识点记录——Java基础篇

Java基础

Q:面向对象三大特性

  • 封装、继承、多态;
  • 从一定角度上看,封装和继承是为了多态而准备的

多态

存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象

实现的三种方式

  • 重写
  • 接口
  • 抽象和抽象方法

Q:类的初始化顺序依次是?
(静态变量、静态代码块)>(变量、代码块)>构造方法

Q:Integer的比较

当直接给Integer赋int值时,如果值得范围为[-128,127],Integer直接从缓存中取Integer对象,因此,当直接赋的int值处于[-128,127]时,Integer对象为相同的对象。而通过new方式取的Integer对象,是直接从堆里面分配的对象,因此,不管具体的int值为多少,==判断的结果都是false

Q:equals与==的区别

  • ==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同
  • ==是指对内存地址进行比较 , equals()是对字符串的内容进行比较
  • ==指引用是否相同, equals()指的是值是否相同

Q:Java几种集合

  • List: List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象
  • Set: 不允许重复的集合。不会有多个元素引用相同的对象。
  • Map: 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。

Q:对java的集合List有了解吗?

  • 对于随机访问 get、set ArrayList效率优于LinkedList,因为LinkedList要移动指针遍历;
  • 对于新增add和删除remove操作,Linkedlist要优于ArrayList,因为ArrayList要移动数据
  • Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
nul ArrayList LinkedList Vector
底层 动态数组 链表 动态数组
特性 随机访问get和set性能高(Linked需要移动指针遍历) 新增删除操作add和remove性能高(因为ArrayList要移动数据)(ArrayList在添加和删除的时候,底层是创建一个新的数组,而LinkedList却只要修改一下指针就ok了) 支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢
使用 查询多,使用ArrayList 添加\删除多,使用LinkedList 和ArrayList一样

Q:对java的集合Map有了解吗?

Map HashMap HashTable ConcurrentHashMap
底层 数组+链表,数据量大时会转化为红黑树进行保存 和hashmap差不多,但是key、value不允许为null,线程安全,效率较慢 线程安全,ConcurrentHashMap采用了分段锁技术,没有同Hashtable一样锁住全部数据,效率较比HashTable高

Q:调用start()方法和调用run()方法的区别

1、start()方法是开启了一个线程,会自动调用run()方法,此时程序会自动往下执行,此时不等start()方法执行完。
2、如果线程直接调用run()方法,则程序会等run()方法执行完再往下执行。

Q:对反射有了解吗?

基础

  • 主要涉及到的类:Class类、Field类(类属性)、Method类(类方法)、Constructor类(构造方法)
  • 带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。
  • 访问私有方法、成员函数

使用场景

  • 组件化时,通过反射获取各个组件初始化类,进行初始化(实现了统一接口)
  • 使用ViewPager + Fragment 时,如果传入一个包含Fragment的List,会造成对Fragment的强引用,造成内存泄漏

简单使用

获取类、实例化

      Class<?> mClass = Class.forName("reflect.Person"); // 必须是全路径
      System.out.println(mClass.getName());  // 获取类名
      // output : reflect.Person

      Person person = (Person) mClass.newInstance();
      person.setAge(1);
      person.setName("LiHan");
      System.out.println(person.getName() + "age is " + person.getAge());
      // output : LiHanage is 1

获取构造函数

     Constructor[] constructors = mClass.getConstructors();        // 获取public构造方法包括私有构造方法
     Constructor[] constructors2 = mClass.getDeclaredConstructors(); // 获取所有构造方法包括私有构造方法

    // 使用私有构造函数
    Constructor constructor = mClass.getDeclaredConstructor(String.class); // 获取到私有构造函数
    constructor.setAccessible(true);
    Person person2 = (Person) constructor.newInstance("person2");
    System.out.println(person2.getName());
    

获取、修改成员变量

        ...
        //接上

        // 获取公共成员变量
        Field[] fields = mClass.getFields();

        // 获取所有成员变量
        Field[] fields2 = mClass.getDeclaredFields();
          
        // 修改成员变量
        Person person1 = (Person) mClass.newInstance();
        Field tag = mClass.getField("TAG");
        Field name = mClass.getDeclaredField("name");
        tag.setAccessible(true);
        name.setAccessible(true);
        tag.set(person1,"newTAG"); // 传入操作对象和值
        name.set(person1,"newName");
        System.out.println(person1.TAG + "  " + person1.getName());

获取、使用方法

      // 获取到所有方法(包括Object类的)
     Method[] methods = mClass.getMethods();
      // 获取到“私有方法” 即Person类的所有方法
     Method[] declaredMethods = mClass.getDeclaredMethods(); 

     Method setTAGMethod = mClass.getDeclaredMethod("setTAG",String.class);

     setTAGMethod.setAccessible(true);
     setTAGMethod.invoke(person1,"reflectName");
     System.out.println(person1.TAG);

Q:String,StringBuffer与StringBuilder的区别

  • String 不是基本数据类型,而是一个对象
  • String 底层是一个final类型的 char[ ] 因此String的值是不可变的,每次对String的操作都会产生新的String对象;
  • 创建字符串的时候先查找字符串缓冲池中有没有相同的对象,如果有相同的对象就直接返回该对象的引用,如果没有相同的对象就在字符串缓冲池中创建该对象,然后将该对象的应用返回。
  • StringBuffer 和 StringBuilder 底层是可变的 char[ ]
String StringBuilder StringBuffer
不可变 可变 可变
线程安全,速度较慢 线程不安全,速度较快

Q:强软弱虚

  • 强引用:在内存不足时不会被回收。平常用的最多的对象,如新创建的对象。
  • 软引用:在内存不足时会被回收。用于实现内存敏感的高速缓存。
  • 弱引用:只要GC回收器发现了它,就会将之回收。用于Map数据结构中,引用占用内存空间较大的对象。
  • 虚引用:在任何时候都可能被垃圾回收器回收。

Q:Java 浅克隆和深克隆的区别

  • 浅克隆:

是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
(子类对象还是指向同一个地址)

  • 深克隆:

不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。(引用的对象也进行了克隆)

  • 实现深克隆:

重写父类的clone方法,在clone调用包含的子类的clone克隆方法

Q:抽象类和接口的区别有哪些

  • 抽象类要被子类继承,接口要被类实现。
  • 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
  • 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
  • 接口是设计的结果,抽象类是重构的结果。
  • 抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。
  • 抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
  • 抽象类主要用来抽象类别,接口主要用来抽象功能。

多线程

Q:线程的几个常用方法

  • start 开启一个线程
  • run 执行任务的具体逻辑
  • join 阻塞当前调用它的线程,等待join执行完毕,当前线程继续执行。
  • Thread.currentThread() 获取执行当前方法的线程
  • Thread.yield() 降低线程优先级,可能会使线程进入暂停状态
  • Thread.sleep(ms) 使当前线程在指定时间内休眠

Q:wait和sleep方法的不同

  • wait()来自Object类,sleep()来自Thread类
  • 调用 sleep()方法,线程不会释放对象锁。而调用 wait() 方法线程会释放对象锁;
  • sleep()睡眠后不出让系统资源,wait()让其他线程可以占用 CPU;
  • sleep(millionseconds)需要指定一个睡眠时间,时间一到会自然唤醒。而wait()需要配合notify()或者notifyAll()使用

Q:多个线程如何按顺序执行

使用Thread的join方法
先执行 t1,ti执行完后再执行t2:

t1.start();
t1.join(); 
t2.start();

加入synchronized关键字

发布了27 篇原创文章 · 获赞 6 · 访问量 1647

猜你喜欢

转载自blog.csdn.net/weixin_41802023/article/details/103298455