Android面试相关(一) java基础篇

Android相关的开发工作大部分都是基于java语法的,底层的另说,所以面试时良好的java基础是很重要的。

1.面向对象的特征:

(1)抽象:将一类对象的共同特征总结出来构造类的过程。

(2)继承:从已有类得到继承信息,创建新类的过程。

(3)封装:把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

(4)多态:允许不同子类型的对象对同一消息做出不同的响应。

2.Java中的内存管理机制:

Java中把内存大致分为三个部分:

(1)方法区:也叫静态存储区,在这里存储的是直接书写的常量,静态数据,全局变量,在这里的数据在整个程序运行时一直都会存在。

(2)栈区:方法体内的局部变量,基本数据类型的变量,对象的引用等;

(3)堆区:也叫动态内存分配,new 和 构造器创建的对象保存在这里;

举个例子: String str=new String(“hello”);

str这个引用存储在栈上,new出来的字符串对象存储在堆上,hello这个字符串存储在方法区内;

3.String ,StringBuilder和StringBuffer的区别:

(1)String为只读字符串,String引用的字符串内容是不能改变的,StringBuffer和StringBuilder的值可以直接修改;

(2)StringBulider与StringBuffer的方法完全一样,但是StringBulider的所有方法没有被Synchronized修饰,所以是单线程,是线程不安全的,但是其效率最高;

(3)String赋予新值会重新开辟内存地址,而StringBuffer和StringBuilder则采用append和insert等方法来改变字符串的值,是在原有对象的内存上进行操作,所以大量字符串拼接时采用StringBuffer或StringBuilder,少量可采用String的“+”;

(4)这里还有一个比较偏的点:请说出下面程序的输出:

public static void main(String[] args) {

    String s1 = "Programming";

    String s2 = new String("Programming");

    String s3 = "Program" + "ming";

    System.out.println(s1 == s2);

    System.out.println(s1 == s3);

    System.out.println(s1 == s1.intern());
}

正确答案是:false, true ,true;

第一个很好理解,s1和s2的引用不一样,当然是false

第二个我也很纳闷为什么会是true,原来啊,String的+被Java进行了特殊处理,在运算过程中会使用StringBuilder或者StringBuffer代替求和,而这两个在进行字符串的运算时,不会改变其内存地址,内存中已经存在了Programming这个字符串,那么就不会重新开辟内存地址,所以是true;

第三个要知道intern方法的使用,String对象的intern方法会得到字符串对象在常量池中对应的版本的引用(如果常量池中有一个字符串与String对象的equals结果是true),如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用。

4.重载(OverLoad)和重写(Override)的区别:

这个大部分人应该都清楚,这里我总结一下:

(1)重载实现的是编译时的多态,重写实现的运行时的多态,所谓的编译时的多态就是在编译时就能确定执行的是哪个多态方法,否则就是运行时的多态。

(2)重载发生在一个类中,同名方法具有不同的参数列表(参数类型不同,参数个数不同),重写发生在子类与父类中,子类被重写的方法与父类被重写的方法具有相同的返回类型,比父类要更好访问,不能比父类有更多的异常

这里有一个经典的面试题,为什么函数重载不能根据返回类型区分?

答案:因为函数调用时不会指定类型信息,编译器不知道你到底要调用那个方法。

5.GC是什么?为什么要有GC?

GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。

补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:

  • 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
  • 幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
  • 终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。

6.Error和Exception区别

Error类和Exception类的父类都是throwable类

Error:一般指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止
Exception:表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常

7.Unchecked Exception和Checked Exception区别

1、Unchecked Exception

指的是不可被控制的异常,或称运行时异常,主要体现在程序的瑕疵或逻辑错误,并且在运行时无法恢复
包括Error与RuntimeException及其子类,如:OutOfMemoryError,IllegalArgumentException, NullPointerException,IllegalStateException,IndexOutOfBoundsException等
语法上不需要声明抛出异常也可以编译通过
2、Checked Exception

指的是可被控制的异常,或称非运行时异常
除了Error和RuntimeException及其子类之外,如:ClassNotFoundException, NamingException, ServletException, SQLException, IOException等
需要try catch处理或throws声明抛出异常

8.多线程实现的方式

继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程

如何停止一个线程
创建一个标识(flag),当线程完成你所需要的工作后,可以将标识设置为退出标识
使用Thread的stop()方法,这种方法可以强行停止线程,不过已经过期了,因为其在停止的时候可能会导致数据的紊乱
使用Thread的interrupt()方法和Thread的interrupted()方法,两者配合break退出循环,或者return来停止线程,有点类似标识(flag)
(推荐)当我们想要停止线程的时候,可以使用try-catch语句,在try-catch语句中抛出异常,强行停止线程进入catch语句,这种方法可以将错误向上抛,使线程停止事件得以传播
线程的状态转换
这里写图片描述

1、新建(new):创建了一个线程对象
2、可运行(runnable):线程对象创建后,线程调用start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权
3、运行(running):可运行状态(runnable)的线程获得了cpu使用权,执行程序代码
4、阻塞(block):线程因为某种原因放弃了cpu使用权,即让出了cpu使用权,暂时停止运行,直到线程进入可运行(runnable)状态,才有机会再次获得cpu使用权转到运行(running)状态。阻塞的情况分三种:

等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中
同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中
其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态
5、死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期,且死亡的线程不可再次复生

9.什么是线程安全

在多线程访问同一代码的时候,不会出现不确定的结果

如何保证线程安全
对非安全的代码进行加锁操作
使用线程安全的类
不要跨线程访问共享变量
使用final类型作为共享变量
对共享变量加锁操作

Synchronized如何使用

Synchronized是Java的关键字,是一种同步锁,它可以修饰的对象有以下几种

修饰代码块:该代码块被称为同步代码块,作用的主要对象是调用这个代码块的对象
修饰方法:该方法称为同步方法,作用的主要对象是调用这个方法的对象
修饰静态方法:作用范围为整个静态方法,作用的主要对象为这个类的所有对象
修饰类:作用范围为Synchronized后面括号括起来的部分,作用的主要对象为这个类的所有对象

Synchronized和Lock的区别

相同点:Lock能完成Synchronized所实现的所有功能
不同点:

Synchronized是基于JVM的同步锁,JVM会帮我们自动释放锁。Lock是通过代码实现的,Lock要求我们手工释放,必须在finally语句中释放。
Lock锁的范围有局限性、块范围。Synchronized可以锁块、对象、类
Lock功能比Synchronized强大,可以通过tryLock方法在非阻塞线程的情况下拿到锁

多线程的等待唤醒主要方法

void notify():唤醒在此对象监视器上等待的单个线程
void notifyAll():唤醒在此对象监视器上等待的所有线程
void wait():导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法
void wait(long timeout):导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量
void wait(long timeout, int nanos):导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量

sleep和wait的区别

sleep()wait()
是Thread类的方法是Object类中的方法
调用sleep(),在指定的时间里,暂停程序的执行,让出CPU给其他线程,当超过时间的限制后,又重新恢复到运行状态,在这个过程中,线程不会释放对象锁调用wait()时,线程会释放对象锁,进入此对象的等待锁池中,只有此对象调用notify()时,线程进入运行状态

10.数据库

        Class.forName("com.mysql.jdbc.Driver");

        // 打开链接
        System.out.println("连接数据库...");
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

        // 执行查询
        System.out.println(" 实例化Statement对象...");
        stmt = conn.createStatement();
        String sql;
        sql = "SELECT id, name, url FROM websites";
        ResultSet rs = stmt.executeQuery(sql);

        // 展开结果集数据库
        while(rs.next()){
            // 通过字段检索
            int id  = rs.getInt("id");
            String name = rs.getString("name");
            String url = rs.getString("url");

            // 输出数据
            System.out.print("ID: " + id);
            System.out.print(", 站点名称: " + name);
            System.out.print(", 站点 URL: " + url);
            System.out.print("\n");
        }
        // 完成后关闭
        rs.close();
        stmt.close();
        conn.close();

11.网络

一、HttpClient:
HttpClient 是Apache的一个三方网络框架,网络请求做了完善的封装,api众多,用起来比较方便,开发快。实现比较稳定,bug比较少,但是正式由于其api众多,是我们很难再不破坏兼容性的情况下对其进行扩展。所以,Android团队对提升和优化httpclient积极性并不高。android5.0被废弃,6.0逐渐删除。
二、HttpURLConnection
HttpURLConnection是一个多用途、轻量级的http客户端。它对网络请求的封装没有HttpClient彻底,api比较简单,用起来没有那么方便。但是正是由于此,使得我们能更容易的扩展和优化的HttpURLConnection。不过,再android2.2之前一直存在着一些令人烦的bug,比如一个人可读的inputstream调用它的close方法的时候,会使得连接池实效,通常的做法就是禁用连接池。因此,在android2.2之前建议使用稳定的HttpClient,android2.2之后使用更容易扩展和优化的HttpURLConnection。
三、okhttp
支持Android 2.3及其以上版本;
支持Java JDK 1.7以上版本;
okhttp是专注于提升网络连接效率的http客户端。
1、它能实现同一ip和端口的请求重用一个socket,这种方式能大大降低网络连接的时间,和每次请求都建立socket,再断开socket的方式相比,降低了服务器服务器的压力。
2、okhttp 对http和https都有良好的支持。
3、okhttp 不用担心android版本变换的困扰。
4、成熟的网络请求解决方案,比HttpURLConnection更好用。
4、缺点,okhttp请求网络切换回来是在线程里面的,不是在主线程,不能直接刷新UI,需要我们手动处理。封装比较麻烦。

12.json和html

XML的三种原生解析方式

DOM,SAX,PULL
DOM:
内存消耗大 但是便于遍历.打开文档,将其转化为节点树,然后在其用循环的方式,遍历节点,一一查找.
SAX:
速度快,战内存少.但是文件结构信息会丢失,采用的是流的处理方式.从起始标签开始一一往下逐个查找.起始标签与结尾标签作为标记来将一组数据存入一个集合中,想水流一样一直到最尾,然后最后返回集合,集合中就存下了所有的数据(这也应该就是所谓的流处理方式吧).
PULL:
是Android内置,推荐的一种,相对来说有点类似SAX,也是从上往下,但是它还是已文档开始与结尾为条件,在其中间进行查找处理,然后分为不同标签开始逐一查找.

JSON的三种解析方式

原始解析:JSONObject
google的
Gson:
Gson gson = new Gson();
    String str = gson.toJson(obj);
阿里的
Fastjson:

JSON.parseObject(result,MenuBean.class);


持续更新中。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值