1、String类都有什么特点?
字符串是常量, 一旦被赋值,不可被改变
final修饰的类—最终类
2、说说==和equals的区别:
==:比较引用类型比较的是地址值是否相同
equals:比较引用类型默认也是比较地址值是否相同
而String类重写了equals()方法,比较的是内容是否相同
3、什么是StringBuffer?
我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。
而StringBuffer就可以解决这个问题 线程安全的可变字符序列
4、问题: StringBuffer和String的区别?
前者长度和内容可变,后者不可变。
如果使用前者做字符串的拼接,不会浪费太多的资源。
10、为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。
数组和集合类同是容器,有何不同?
集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
20、集合遍历
Object[] toArray()
把集合转成数组,可以实现集合的遍历
Iterator iterator()
迭代器,集合的专用遍历方式
21、List集合底层结构
List的子类特点
ArrayList:
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
Vector:
底层数据结构是数组,查询快,增删慢
线程安全,效率低
LinkedList:
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
ArrayList
A:没有特有功能需要学习
B:案例
a:ArrayList存储字符串并遍历
b:ArrayList存储自定义对象并遍历
Vector
A:有特有功能
a:添加
public void addElement(E obj) -- add()
b:获取
public E elementAt(int index) -- get()
public Enumeration<E> elements() -- iterator()
B:案例
a:Vector存储字符串并遍历
b:Vector存储自定义对象并遍历
LinkedList
A:有特有功能
a:添加
addFirst()
addLast()
b:删除
removeFirst()
removeLast()
c:获取
getFirst()
getLast()
B:案例
a:LinkedList存储字符串并遍历
b:LinkedList存储自定义对象并遍历
泛型概述
是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
格式:
<数据类型>
注意:该数据类型只能是引用类型。
好处:
A:把运行时期的问题提前到了编译期间
B:避免了强制类型转换
C:优化了程序设计,解决了黄色警告线问题,让程序更安全
泛型的前世今生
A:泛型的由来
Object类型作为任意类型的时候,在向下转型的时候,会隐含一个转型问题
B:泛型类
C:泛型方法
D:泛型接口
E:泛型高级通配符
?
? extends E
? super E
(5)我们在哪里使用呢?
一般是在集合中使用。
22:增强for循环
(1)是for循环的一种
(2)格式:
for(元素的数据类型 变量名 : 数组或者Collection集合的对象) {
使用该变量即可,该变量其实就是数组或者集合中的元素。
}
(3)好处:
简化了数组和集合的遍历
(4)弊端
增强for循环的目标不能为null。建议在使用前,先判断是否为null。
23:静态导入(了解)
(1)可以导入到方法级别的导入
(2)格式:
import static 包名....类名.方法名;
(3)注意事项:
A:方法必须是静态的
B:如果多个类下有同名的方法,就不好区分了,还得加上前缀。
所以一般我们并不使用静态导入,但是一定要能够看懂。
24:可变参数
(1)如果我们在写方法的时候,参数个数不明确,就应该定义可变参数。
(2)格式:
修饰符 返回值类型 方法名(数据类型... 变量) {}
注意:
A:该变量其实是一个数组名
B:如果一个方法有多个参数,并且有可变参数,可变参数必须在最后
(3)Arrays工具类的一个方法
asList()把数组转成集合。
注意:这个集合的长度不能改变。
25、Map集合
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map集合和Collection集合的区别?
* Map是双列的,Collection是单列的
* Map的键唯一,Collection的子体系Set是唯一的
* Map集合的数据结构值针对键有效,跟值无关
* Collection集合的数据结构是针对元素有效
26、Map集合使用
map的底层结构是数组+链表,存储时候,对一个元素计算hash码,
将同一个hashcode的元素放到数组相同位置的链表中(这里的数组每个位置存放的是有相同hashcode的链表)
Map集合的遍历
A:键找值
a:获取所有键的集合
b:遍历键的集合,得到每一个键
c:根据键到集合中去找值
B:键值对对象找键和值
a:获取所有的键值对对象的集合
b:遍历键值对对象的集合,获取每一个键值对对象
c:根据键值对对象去获取键和值
27、set集合
(1)Set集合的特点
无序,唯一
(2)HashSet集合
A:底层数据结构是哈希表(是一个元素为链表的数组)
B:哈希表底层依赖两个方法:hashCode()和equals()
执行顺序:
首先比较哈希值是否相同
相同:继续执行equals()方法
返回true:元素重复了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合
C:如何保证元素唯一性的呢?
由hashCode()和equals()保证的
D:开发的时候,代码非常的简单,自动生成即可。
E:HashSet存储字符串并遍历
F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)
(3)TreeSet集合
A:底层数据结构是红黑树(是一个自平衡的二叉树)
B:保证元素的排序方式
a:自然排序(元素具备比较性)
让元素所属的类实现Comparable接口
b:比较器排序(集合具备比较性)
让集合构造方法接收Comparator的实现类对象
28、集合总结
Collection集合总结
Collection
|–List 有序,可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高
|–Set 无序,唯一
|--HashSet
底层数据结构是哈希表。
如何保证元素唯一性的呢?
依赖两个方法:hashCode()和equals()
开发中自动生成这两个方法即可
|--LinkedHashSet
底层数据结构是链表和哈希表
由链表保证元素有序
由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树。
如何保证元素排序的呢?
自然排序
比较器排序
如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
常见的集合
在集合中常见的数据结构(掌握)
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
内存泄露
对象未被正确回收
当对象的引用仍然存在时,但不再需要该对象时,及时设置为null
由于匿名类和内部类会隐式持有外部类的引用,及时设置为null
如果在使用Handler时,使用弱引用方便及时被回收
应用程序启动了一个后台任务,并且该任务的生命周期很长,这可能会导致内存泄漏。在任务完成后及时将相关对象设置为null
Context引用是非常常见的内存泄漏原因。当将一个长生命周期的对象与Context关联时,在onDestory方法设置为null
在使用一些资源,如数据库连接、文件输入/输出流等时,如果在使用完毕后及时关闭
使用缓存是为了提高性能和减少资源使用,在缓存中保持过长时间的对象引用,有可能导致内存泄漏,及时将旧对象移除
sleep和wait区别
sleep是Thread的方法,wait是object的方法
sleep自动唤醒,wait需要被其他线程唤醒
sleep不会释放同步锁,wait会释放同步锁
sleep可以在任一方法使用,wait在同步方法或者同步块中
启动一个线程是start还是run
start是启动线程,run是执行线程
android启动模式应用场景
第一种:standard(默认)就是Android默认的启动模式,就是不显示指定,就是这种模式。
特点:standard模式下,会不断地新建activity实例,都放入同一个task中,即每次转到到该Activity就会创建一个本activity的实例
应用场景:该模式为默认模式,适用于大多数应用场景。
第二种:singleTop
特点:顾名思义,singleTop,如果当前实例在当前的task的栈顶,则直接复用,如果当前实例不再栈顶,则新建实例。
应用场景:
通知消息打开的页面;
耗时操作返回页面;
第三种:singleTask
特点:设置了singleTask的页面,只要是task中有这个实例,就会一直复用,而且每次复用这个已存在的实例,都会清空上面的其他实例,将自己直接提升到栈顶位置,显示自己
应用场景:浏览器、微博等页面
第四种:singleInstance
特点:设置了singleInstance的页面,初始时都是新建一个task栈给这个页面,然后后面一直复用这个栈内的页面。注意,只有这种模式会新建一个栈给初始化的页面。最后返回的规律是,先把本页面所在的栈都出完,然后再弹出下一个栈的每个页面。
应用场景:呼叫来电界面。
activity跳转生命周期变化
1、activity 跳转另一个 activity 生命周期变化 A---跳转----B
A : onCreate --->onStart--->onResume--->onPause--->B: onCreate--->onStart--->onResume--->A: onstop
B------返回---A
B: onPause-->A:onRestart--->onStart-->onResume-->B: onStop->onDestroy
说明:
A--跳转----B
刚打开的时候先执行A的oncreate---onstart---onResume为可视化,当点击了跳转按钮,
在执行A 的 onPause,现在到了B页面,执行B的onCreate---onStart--onResume为可视
化,由于B 现在是可视化状态,所以A页面在B执行到可视化的时候,A 页面执行 onstop
B-----返回---A
由于B 现在处于可视化状态,再返回A的时候直接执行onPause,现在返回到了A页面,
A 页面执行 onRestart----onStart---onResume,重新开始后到了可视化状态,B页面就执行
onStop----onDestroy
RecyclerView 与 ListView 的主要区别
ViewHolder
ListView 需要自定义ViewHolder,判断convertView是否为null,setTag()与getTag()的使用;RecyclerView有规定好的ViewHolder。
布局不同
ListView 只支持垂直方向的,而RecyclerView,它里面的LayoutManager(布局管理类),有横向、竖向、瀑布流、网格等复杂的布局。
数据更新
ListView 数据刷新指的是全部数据刷新。RecyclerView支持局部数据刷新
注:ListView 提供了 setEmptyView 该 API 来让我们处理 Adapter 中数据为空的情况;Recyclerview没有提供
适配器
ListView的适配器继承ArrayAdapter;RecycleView的适配器继承RecyclerAdapter,并将范类指定为子项对象类.ViewHolder(内部类)。
item 事件
ListView是在主方法中ListView对象的setOnItemClickListener方法;RecyclerView则是在子项具体的View中去注册事件。
缓存不同
Recyclerview 四级缓存 是由三个类共同作用完成的,Recycler、RecycledViewPool和ViewCacheExtension。
Listview 二级缓存 通过 ActiveViews和ScrapViews
二者缓存
recyclerview
一级缓存:屏幕内缓存,屏幕内缓存指在屏幕中显示的ViewHolder,ViewHolder会缓存在AttachedScrap、ChangedScrap中
AttachedScrap:未与RecyclerView分离的ViewHolder列表
ChangedScrap:数据已经改变的viewHolder列表
二级缓存:屏幕外缓存,当列表滑动出了屏幕时,ViewHolder会被缓存在 CachedViews ,其大小由ViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,
可通过Recyclerview.setItemViewCacheSize()动态设置。
三级缓存:RecycledViewPool, RecycledViewPool类是用来缓存ViewHolder用,
如果多个RecyclerView之间用setRecycledViewPool(RecycledViewPool)设置同一个RecycledViewPool,他们就可以共享ViewHolder。
四级缓存:ViewCacheExtension开发人员可自定义的一层缓存,是虚拟类ViewCacheExtension的一个实例,
开发人员可实现方法getViewForPositionAndType来实现自己的缓存。
listview
一级缓存:ActiveViews 活动等view,这些view是布局过程开始屏幕上的view。layout开始时这个数组被填充,
layout结束,ActiveViews中的view移动到ScrapViews。ActiveViews代表了一个连续范围的views,
其第一个view的位置存储在FirstActivePosition变量中。
二级缓存:ScrapViews 废弃的view,无序的被adapter的convertView使用的view的集合ScrapViews是多个list组成的数组,
数组的长度为viewTypeCount,每个item是个list,所以每个list缓存不同类型item布局的view
Glide缓存机制
如果加载过图片直接去内存缓存获取,否则根据ImageView尺寸去磁盘缓存获取,如果磁盘缓存也没有直接加载网络上的图片
如何实现磁盘缓存
1、将图片数据转换为一个KRY值
2、根据KEY值去磁盘获取,如果有直接使用
3、如果没有,就从内存取出BitMap图片存进磁盘
线程池有哪些?
1、newSingleThreadExecutor:创建一个单线程的线程池,根据提交任务的顺序进行执行
2、newFixedThreadPool:创建一个固定大小的线程池,每接收到任务就创建一个线程,直至到线程池最大数量
3、newCachedThreadPool:创建一个可缓存的线程池,不会对线程池做缓缓存理,完全取决于操作系统
能够支持创建多少线程
4、newScheduledThreadPool:创建一个大小无限制的线程池,可支持定时及周期性的任务执行需求
对线程池的理解
1、通过重复利用线程,避免线程创建和销毁造成的消耗,降低资源消耗
2、接收到任务时可立即执行,提高执行效率和响应速度
3、使用线程池可以进行统一的分配,不停地创建线程会导致资源消耗和系统不稳定,提高对线程的可管理性
如何保证三个线程有顺序的执行?
可以使用线程的 join() 方法,在一个线程中执行另一个线程,当另一个线程执行完毕则当前线程继续执行
先执行哪一个线程都可以
thread2.start();
thread3.start();
thread1.start();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
Log.e("TAG","----thread1-----");
}
});
Thread thread2= new Thread(new Runnable() {
@Override
public void run() {
try {
// 等待thread1线程执行完,在执行thread2
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG","----thread2-----");
}
});
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
try {
// 等待thread2线程执行完,在执行thread3
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG","----thread3-----");
}
});
如何优化WebView?
1、启动WebView的缓存策略,自动缓存页面,方便后期访问同一页面
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);// 启用WebView缓存
2、启动硬件加速,利用GPU渲染网页内容
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);// 启用WebView硬件加速
3、网页预加载:在当前页面预加载下一个页面,加快切换速度,方法如下:
WebView webView=new WebView(MainActivity.this);
webView.setWebViewClient(new WebViewClient(){
String urlLoad="";
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
urlLoad=url;
webView.loadUrl(url);//开始预加载页面
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
webView.setVisibility(View.VISIBLE);//显示加载的内容
}
});
4、离线缓存,将页面先缓存到本地,没有网的情况下使用缓存,缓存模式如下:
LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。
LOAD_CACHE_NORMAL: API level 17中已经废弃, 从API level 11开始作用同LOAD_DEFAULT模式
LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
WebSettings settings = webView.getSettings();
settings.setAppCacheEnabled(true);
if (判断网络) {
//当前有可用网络
settings.setCacheMode(WebSettings.LOAD_DEFAULT); //设置 缓存模式( 根据cache-control决定是否从网络上取数据。)
} else {
//当前没有可用网络
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //设置 缓存模式(只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。)
}