面试题:
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);
-