面试题:
1. 泛型:
1. 什么是泛型,能解决什么问题
2. 说说java中的泛型的工作机制
3. 在泛型中extends和super关键字的区别
2. Android 8.0适配?
1. 面试题解题
1.1 泛型
1.1.1 什么是泛型
泛型是Java SE1.5引入的,泛型本质是参数化类型,将所操作的数据类型指定为一个参数,该参数类型可以用在类、接口、方法中。分别叫做泛型类、泛型接口、泛型方法。
- 泛型类
泛型类用于类的定义中,比如List,Set,Map等。
/**
* 此处的T是泛型标识,可以是任意的大写字母
* 在调用时必须指定T的具体类型:new People<Integer>(60);
*/
public class People<T> {
private T t;
public People(T t) {
this.t = t;
}
}
- 泛型接口
同泛型类一样,用于接口的定义中,见下面的例子。
public interface Age<T> {
T getAge();
}
public class People implements Age<Integer>{
@Override
public Integer getAge() {
return new Random().nextInt(100);
}
}
- 泛型方法
需要在方法中使用的泛型如果没有在类和接口中定义过,那么必须在方法中定义后才可使用。
/**
* public 和返回值E中间的类型申明是必需的,因为只有申请了该类型,才能在方法中使用
*/
public <E> E getInfomation(Class<E> eClass) throws IllegalAccessException, InstantiationException {
E e = eClass.newInstance();
return e;
}
1.1.2 泛型能解决什么问题
- 在编译时检查参数类型,避免异常发生
- 消除强制类型转换
- 提高代码复用率
1.1.3 说说java中的泛型的工作机制
Java泛型是编译时技术,在运行时不包含泛型信息,仅仅是Class的实例中包含类型参数的定义信息。它是通过Java编译器的擦除前端来实现的,可以认为是从源码到源码的转换,从泛型源码转为非泛型的代码。它有几个特点:
- 不能依靠泛型做类型转换
- 同一个泛型类,在被调用时类类型是一样的,无论传入的泛型类是否一样
1.1.4 在泛型中extends和super关键字的区别
使用底下的例子来说明,extends是上界通配符,指定类的上边界。它只能取,不能存,因为你不清楚具体存的是哪个实现类,所以无法存入。
super是下界通配符,指定类的下边界,它只能存,不能取,因为根本不清楚取出的数据是什么实现类,只能指定为Object。
class Food{}
class Fruit extends Food{}
class Apple extends Fruit{}
class Banana extends Fruit{}
public void testExtends(List<? extends Fruit> fruits){
// fruits.add(new Apple());
Fruit fruit = fruits.get(0);
}
public void testSuper(List<? super Fruit> list){
// Object object = list.get(0);
list.add(new Fruit());
}
1.2 Android 8.0适配?
1.2.1 Android8.0 通知适配
Android 8.0加入了ChannelId和ChannelGroup的概念,如果在创建通知的时候不加ChannelId,通知是不会被唤起的。
- 创建小组,这个步骤可有可无
- 创建ChannelId(为了简单,都简写写死,如果创建了小组,需要给ChannelId配置GroupId)
NotificationChannel notificationChannel = new NotificationChannel("track_id", "track_name", NotificationManager.IMPORTANCE_LOW);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
- 在构建通知时,加入ChannelId(比以往多加一个参数ChannelId)
Notification notification = new Notification.Builder(this, "track_id").build();
1.2.2 广播限制
Android 8.0的应用无法在其清单文件中注册隐式广播接收器。
两种方案:
- 动态注册广播
- 指定包名,作为显示广播发送
1.2.3 后台服务适配
Android 8.0 对应用在后台执行的操作增加了限制,当应用处于后台时,不允许再启动服务。Android8.0提供了方法,在后台可以创建前台服务,下面看下步骤
- 启动前台服务
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
context.startForegroundService(service);
}else{
context.startService(service);
}
- 建立前台服务通知并调用
startForeground(1,notification)
如果是IntentService,这部分逻辑需要加到onHandleIntent中,因为onCreate并不是每次调用startService都会调用。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel notificationChannel = new NotificationChannel("track_id", "track_name", NotificationManager.IMPORTANCE_LOW);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
Notification notification = new Notification.Builder(this, "track_id").build();
startForeground(1,notification);
}
- 关闭前台服务
service.stopForeground(true);
1.2.4 apk安装权限
Android 8.0 去除允许未知来源选项,需要用户手动确认,如果没有适配,覆盖安装时直接闪退。
- 最简单的解决方式就是,在Manifest文件中配置请求安装权限,这样在app调用安装界面时,系统会询问用户授权。
- 当然,你可以可以做的更复杂一些。
- 清单文件中配置
REQUEST_INSTALL_PACKAGES
权限 - 调用
packageManager.canRequestPackageInstalls()
获取是否已有该权限
PackageManager packageManager = getApplicationContext().getPackageManager();
boolean canInstallApk = packageManager.canRequestPackageInstalls();
- 如果没有权限,则弹框提示,点击确定跳转用户授权页面(一般更多的是使用startActivityForResult,授权完成继续安装)
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
startActivity(intent);