This is my thrid blog web site.

0%

从Spring 到Vue 4 关于Android

为什么会扯到Android呢,提起java,自然想起Android了呗。

java有java虚拟机,Android有dvm和art。

这三者有什么异同呢。

第一肯定是指令集不同。但是我也想不起具体哪个打哪个了。等下查查资料。

另外,jvm跑的是.class而dvm跑的是.dex。 art也是.dex.

从.class到.dex经历了什么呢,为什么要这样做呢?这中间的具体流程是怎样的呢?

以及,dvm和art有什么不同呢,为什么要这样做呢? 怎样实现的呢? 原理是什么呢?

说起Android虚拟机。我们都知道Android是一个基于Linux的操作系统,那么Android与Ubuntu有什么区别呢。

Android应用正在跑的进场,与Linux中的进程有什么区别,各自是怎样的呢?

一个Android应用从

  • 下载
  • 安装
  • 手机桌面获取安装包信息
  • 启动应用程序
  • 应用程序挂起
  • 待机
  • 关闭

发生了什么

下载自然是http请求,io操作。但是具体怎么实现呢,还得查一下。

安装就涉及到art dvm的区别了

手机获取安装包信息,就涉及到各种manager的关系了。

启动应用程序,就涉及到Android启动模式的相关问题了。

Android声明周期

Android四大组件

四大组件的相关

四大组件与进程的关系

四大组件的通信方式呢

那进程的通信方式呢

与Linux有什么区别呢

与原生的通信方式呢。

Android数据库。事务,触发器

  • greendao
  • realm
  • room

Android事件分发机制

分发机制首先都有屏幕,那Android window相关呢

另外就是recyclerview, 请问recyclerview

Android framework

  • Activity Manager
  • Window Manager
  • Content Provider
  • View System
  • Notification Manager
  • Package Manager
  • Telephony Manager
  • Resource Manager
  • Location Manager
  • XMMP Service

Android

  • Linux Kernel
  • Libraries & android runtime
  • application framework
  • application

FixBug-引发bug的原因在于规划

刚修了一个bug。bug的表现是数据库到显示列表的过滤规则失效。

引发bug的原因在于:

  • 初始规划不科学,可行的情况下存有漏洞
  • 中间经过要求后修改了代码逻辑,但是没有做足够有效的验证

偏算法的逻辑代码一定要有完整的规则,用例,测试,用例图等。不然后续出错后调整的成本太大

笔试,还挺意思

  • 逻辑题
  • 其他
    • mipmap是什么
    • unit生命周期,
  • 算法题

Mipmap

//todo

unit生命周期

//todo

算法题

无序数组求第二小数

求数组最大子数组

华为云核心网 通用软件工程师 20200310

  • 自我介绍
  • 语言
    • java & JavaScript
  • 项目经历
    • miui的经历
  • JVM GC
    • 发展逻辑滤了一遍
  • 计算机网络
    • ISO 7层
      • 只记得5层了,忘记了七层是什么
    • 子网掩码
      • 255.255.255.0的局域网能分配多少个ip
        • 答错了,255.255.255.0 和255.255.255.255都不能用作ip
    • 面试的这个视频 7层
      • 随便说了一下
  • 数据结构
    • 顺序表 链表
      • 怎样选择使用
    • 平衡二叉树的定义
      • 没答出来,答了二叉排序树。定义是左右子树高度差小于1
  • 算法

算法题

1
2
let a = "www.abc.com"
a.split('.').reverse().join('.')

二面

  • 自我介绍
  • java , vue ,spring 都问都讲了,偏问项目
  • 不太记得了
  • 算法题

算法题

数组中有正数和负数,正数代表向右,负数代表向左。当两数字相撞时取绝对值大的数字,保证保持整个数组稳态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
let deal = function (arr) {
let stack = []
arr.map(i => {
console.info(stack)
if (stack.length == 0) {
stack.push(i)
} else {
// duibi tail he i
let t = stack[stack.length-1]
if (t * i > 0) {// 同方向
stack.push(i)
} else if (t * i <0) {//不同方向
if (t <0 && i >0){
stack.push(i)
} else if (t> 0 && i <0){
//要撞
let value = t + i
value = value > 0 ? t:i
stack[stack.length-1] = value
//维持前面稳定
let change = stack.length > 1
while(change) {
t = stack.pop();
tp = stack.pop();

if (tp > 0 && t <0) {
value = tp + t
value = value > 0 ? tp:t
stack.push(value)
} else {
change = false
stack.push(tp)
stack.push(t)
}}}}}
})
return stack
}

从Spring 到Vue 3 关于Java

有什么事Java经常会被问到但是我一直记不住的呢.

基础

Java的基础类型?

int long short byte char boolean double float

声明基础类型的时候发生了什么?

例如

1
2
3
4
5
6
public class Main {
public int a;
//在栈中分配了空间给a
public int b = 0;
//在栈中分配了空间给b同时在常量区中查找变量0,如果有则栈中b指向该值
}

String 类型

1
2
3
4
5
6
public class Main {
public String c = "c";
public String d = "das";

public String e = c + d;
}

引用类型

关键字

transient

可序列化的对象中不需要进行序列化的变量

volatile

每次写的的时候从内存读取

atomic

####

其他

Java 链表

Java List

  • ArrayList
    • 数组
  • Vector
    • 数组
    • 线程安全
  • LinkedList
    • 链表

数组实现: 查找快,增删慢
链表实现: 查找慢,增删快

Java HashSet

    • 调用hashCode,计算存储位置
      • 进行equals比较
        • 没用元素/比较结果为false则存

Java Collection

Java HashMap

hash冲突

拉链法解决

初始容量,加载因子

线程不安全,

hashtable

线程安全

散列表

key value不能为空

支持Enumeration

ConcurrentHashMap

线程安全版HashMap

增加了segment层,每次针对单个segment加锁

LinkedHashMap

  • LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
  • HashMap无序;LinkedHashMap有序,可分为插入顺序和访问顺序两种。如果是访问顺序,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。
  • LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。
  • LinkedHashMap是线程不安全的

我看的这里

TreeMap

基于红黑树的NavigableMap,线程非安全,不允许null,存入需要实现comparable接口或实现comparator接口排序

JVM相关

jvm运行时数据区

  • 方法区 method area
  • 虚拟机栈 VM stack
  • 本地方法栈 native method stack
  • 堆 heap
  • 程序计数器 program counter register

###程序计数器

  • java 方法
    • 正在执行的虚拟机字节码的地址
  • 本地方法
    • undefined

java 虚拟机栈

  • 线程私有
  • java方法执行的内存模型。
  • 每个方法在执行时都会创建一个栈帧 Stack Frame
    • 局部变量表
      • 编译器可知的各种基本类型(boolean, int,long, short, byte, double, float, char)
      • 对象引用类型(refrence)
      • returnAddress类型
    • 操作数栈
    • 动态链接
    • 方法出口

本地方法栈

  • 线程共享

方法区

  • 共享内存
  • 包含
    • 已被虚拟机加载的类信息
    • 常量
    • 静态变量
    • 即时编译器编译后的代码等数据
  • 运行时常量池
    • 存放编译期间生成的各种字面量和符号引用。
    • 内存有限

直接内存

不知道

HotSpot

后续再研究吧

对象的创建

对象的布局

###对象的访问定位

GC

Java 反射

Java 类加载

双亲

线程

1
2
3
4
5
6
7
8
9
10
11

new Thread(new Runnable() {
@Override
public void run () {


}
}).start()

//run的话只是正常运行,不会启动新线程
//如何验证?

Callable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface Callable<V> {
V call() throws Exception;
}

public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();

V get() throws InterruptedException, ExecutionException;

V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}

public class FutureTask<V> implements RunnableFuture<V> {
...
}

线程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface Executor {
void execute(Runnable command);
}

public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();

boolean isShutdown();
boolean isTerminated();

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
}

public class Executors {
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
...
}

四种线程池

  • newCachedThreadPool
    • 如无线程则新建。
    • 一定时间无使用则销毁
  • newSingleThreadExecutor
    • 维持一个线程
  • newFixedThreadPool
    • 最大值前一个任务一个线程
  • newScheduledThreadPool
    • 大小无限

线程异常则再加一新的线程

关闭方法

  • shutdown
    • 不接受新任务,任务结束后停止
  • shutdownNow
    • 尝试停止,返回未执行任务

线程同步

  • 同步方法
  • 同步代码块
  • volatile
  • 重入锁
    • ReentrantLock()
  • ThreadLocal
  • LinkedBlockingQueue
  • 原子变量

equals

先判断类型,在判断值。可重写

hashCode

返回

从Spring 到Vue 2 Spring IOC&AOP

  • 控制反转 IoC (Inversion of controll)
  • 切面编程 AOP Aspect Oriented Programming
    • Java 代理
      • 动态代理
      • 静态代理

IOC

IOC,Inversion of Controll ,控制反转。我一直无法理解这东西到底是什么,为什么起这么一个反人类的名字。

java简单例子介绍IOC和AOP

DI Dependency Inject 依赖注入

依赖注入和控制反转的理解,写的太好了。

DL Dependency Lookup 依赖查找

  • 依赖拖拽
  • 上下文查找

AOP 切面编程

切面编程的简单意思大概就是,把代码切成3层。中间的夹心层是原先的逻辑代码,前后的饼干层是由AOP方式实现的通用逻辑代码。

静态代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

public interface AbcService {
public void doing();
}

public class AbcServiceImpl implements AbcService {
public void doing() {
System.out.println('doing');
}
}

public class AbcServiceProxy implments AbcService {
private AbcService abcService;

public AbcServiceProxy (AbcService service) {
abcService = service;
}

@Override
public void doing() {
System.out.println("doing start")
abcService.doing()
System.out.println("doing end")
}
}
动态代理

动态代理的实现方式就是通过

Proxy.newProxyInstance方法,将需要代理的类,方法,以及参数传递到对应的 InvocationHandler内,然后在调用方法的前后增加想要的逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AbsServiceDynamicProxy {

public static AbcService (AbcServiceImpl serviceImpl) {
return new Proxy.newProxyInstance(serviceImpl.class.getClassLoader()
,logger.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before proxy");
method.invoke(serviceImpl,args);
System.out.println("after proxy")
return null;
}
})
}
}
相关

从Spring 到Vue (一) Spring

从去年六月份开始使用Spring+Vue开发前后端,那么原理是什么呢?我还不知道,这是我对自身知识结构的梳理。

Spring 是什么东西

Spring 是一个后端框架,它用于开发后端。和他平级的还有 ktorexpress等。

当然Spring远不止此,但是从一个非java后端人士的角度来说,暂时就这样把。

使用Spring进行开发与使用原生Java的区别

我为什么需要使用Spring呢,假如我需要实现一个http服务。我为什么不使用原生的java api帮助我实现一个简单的http服务器呢?

HTTP服务器

由此,让我先梳理一下http服务器做了什么事情。

  • 响应网络请求,返回api接口内容
  • 响应网络请求,返回html资源
  • 与mysql等进行通信。
  • 从服务器端进行请求,获取内网数据

Java Api 实现HTTP服务器

使用 com.sun.net.httpserver 包进行相关操作。我本身没有尝试过进行这样的操作,因为以往实现简单HTTP服务时我更倾向于使用express等node相关的技术栈,因为他们更

总而言之,通过官方给予我们的com.sun.net.httpserver包,我们可以简单得实现一个REST API,但是关于:

  • 认证
  • xxxx我没想好得内容,使用Spring会更加方便。

Spring 帮我们做了什么呢

现如今我想要使用spring搭建一个http服务器

Retrofit 源码 part 1

Retrofit 大致上就是动态代理+注释处理

简单来说

如果我们要进行一个像这样的网络请求

1
2
3
GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

摘自retrofit

其内部的过程是这样的

  • retrofit.create()

    • Proxy.newProxyInstance 创建一个java动态代理
      • loadServiceMethod() 调用这个方法
        • parseAnnotations 对GithubService.class内的注释进行处理
          • RequestFactory.parseAnnotations (处理注释)
          • HttpServiceMethod.parseAnnotations (与Okhttp关联)
      • loadServiceMethod().invoke = HttpServiceMethod.invoke 方法调用时会对应调用
  • service.listRepos == Proxy.InvocationHandler.invoke

下面看看具体内容.

create()

Retrofit 的源码我们从Retrofit.create这个方法开始看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];

@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}

在craete()中,先对参数final Class service做一个校验,是否是一个interface,是否有继承自其他interface之类的。

这一部分的核心是返回了一个 Proxy.newProxyInstance(...) , 使用Java 动态代理。同时动态代理的 InvocationHandler 的 invoke()方法的实现与service的注释相关.

我们看到这一部分

1
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

loadServiceMethod

每次执行代理的方法的时候,执行loadServiceMethod.invoke, 所以就是说 Retrofit.create()返回的结果由动态代理帮助实现。那么怎么样把service的方法调用之后就实现网络请求呢?这就由注释实现了。
loadserviceMethod的相关代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;

synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}

这里面我们需要关注的是

1
resuslt = ServiceMethod.parseAnnotations(this, method);

parseAnnotations

很明显这个是对注释进行处理,那么我们需要关注parseAnnotations()做了怎么样的处理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}

return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

abstract T invoke(Object[] args);
}

ServiceMethod的源码很短,简单看来, ServiceMethod.parseAnnotations(…) 完成了两件事

  • 从 retrofit, method 中取得了RequestFactory类的示例retrofitFactory
  • 将 retrofitFactory作为参数交由 HttpServiceMethod处理.

RequestFactory.parseAnnotations(retrofit, method)

这里是真正的对parseAnnotation 进行处理,为什么这么说呢,read the fucking code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}

RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
isFormEncoded = builder.isFormEncoded;
isMultipart = builder.isMultipart;
parameterHandlers = builder.parameterHandlers;
}

...

static final class Builder {
...

Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}

RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...

return new RequestFactory(this);
}


private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}

...
}
}

HttpServiceMethod

再 HttpServiceMethod.parseAnnotations中 再次将retrofit ,method进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);

...
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
...
}

从这里开始 retrofit 和method转化为
requestFactory callFactory callAdapter responseConverter作为参数构建 HttpServiceMethod实例。
所以我们需要去查看HttpServiceMethod是来干什么的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
CallAdapter<ResponseT, ReturnT> callAdapter,
Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.callAdapter = callAdapter;
this.responseConverter = responseConverter;
}

@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
...
}

可以看出,当 service里面的方法被执行的时候,是由callAdapter.adapt()处理一个OkHttoCall完成的。
到此为止,retrofit与okhttp之间的联系也就找到了.

我对动态代理也不熟悉,暂时到此为止,。

Android AppCompatActivity

关系

  • extends FragmentActivity
  • implements AppCompatCallback, SupportParentable, DelegateProvider

与Activity 比较

setContentView

AppCompatActivity的setContentView ,调用this.getDelegate().setContentView(…)
而Acitivity的setContentView调用this.getWindow().setContentView(…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// AppCompatActivity
public void setContentView(View view, LayoutParams params) {
this.getDelegate().setContentView(view, params);
}

public void setContentView(@LayoutRes int layoutResID) {
this.getDelegate().setContentView(layoutResID);
}

// Activity
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}

AppCompatActivity的setContentView调用的时候会调用一个this.getDelegate()