java 复习资料

java基础

1,面向对象和面向过程的区别
2,java的三大特性


封装,继承,多态

3,OverLoad与Override的区别

1
2
3
4
5
6
7
8
9
10
11
Override(重写,覆盖)
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为final不能被重写。
Overload(重载,过载)
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。

4,构造器不能被修饰Override
5,访问控制符public,protected,private,以及默认的区别

1
2
3
4
5
作用域 当前类 同包 子类 其他
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×

6,String和StringBuffer、StringBuilder的区别

1
2
3
4
5
6
7
8
9
10
11
可变与不可变
String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符
数组保存字符串,如下就是,可知这两种对象都是可变的。
char[] value;
线程是否安全
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

7,抽象类和接口的区别

1
2
3
4
5
6
7
1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
  2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
  3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
  4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

8,自动装箱与拆箱

1
2
3
4
5
6
7
8
9
10
11
12
基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。
基本数据与对象的区别
如:int t = 1; t. 后面是没有方法滴。
Integer t =1; t. 后面就有很多方法可让你调用了。
Integer i = 100; // 自动装箱
相当于编译器自动为您作以下的语法编译:Integer i = Integer.valueOf(100);
Integer i = 10; //装箱
int t = i; //拆箱,实际上执行了 int t = i.intValue();
注意:integer值得默认大小是-127-128

7,泛型

1
2
3
4
5
6
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,
类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,
将泛型java代码直接转换成普通java字节码。
类型擦除的主要过程如下:
1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
2.移除所有的类型参数。

8,Java中的集合类及其关系图
关系图
微服务架构图

1
2
3
4
5
6
7
8
9
10
11
12
 上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,
折线边框的是抽象类,比如AbstractCollection,AbstractList,AbstractMap等,
而点线边框的是接口,比如Collection,Iterator,List等。
  是否有序 是否允许元素重复
Collection 否 是
List 是 是
Set AbstractSet 否 否
  HashSet 否 否
  TreeSet 是 否
Map AbstractMap 否 使用key-value来映射和存储数据,key必须唯一,value可以重复
  HashMap
  TreeMap 是(用二叉排序树)

9,HashMap的实现原理
见此链接
10,HashTable实现原理
见此链接
11,HashMap与HashTable的区别

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
第一,继承不同。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
第二
Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,
可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
如果为了要线程安全,可以使用CurrentHashMap
第三
Hashtable中,key和value都不允许出现null值。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
第四,两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
第五
哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
第六
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

12,ArrayList和vector区别

1
2
1) Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。

13,ArrayList和LinkedList区别及使用场景
区别

1
2
3
4
5
6
7
ArryList初始化时,elementData数组大小默认为10
每次add()时,先调用ensureCapacity()保证数组不会溢出,如果此时已满,会扩展为数组length的1.5倍+1
然后用array.copy的方法,将原数组拷贝到新的数组中;线程不安全。
LinkedList是基于双链表实现的:
使用header的优点是:在任何一个条目(包括第一个和最后一个)都有一个前置条目和一个后置条目,
因此在LinkedList对象的开始或者末尾进行插入操作没有特殊的地方;

使用场景
(1)查询操作多,ArrayList对象要远优于LinkedList对象;

(2)修改和删除操作多,LinkedList对象要远优于ArrayList对象;

14,static和final区别和用途
static

1
2
3
4
修饰变量:静态变量随着类被加载时被完全初始化,在内存中只有一个,并且JVM只会为它分配一次内存,所有类共享此变量。
修饰方法:在类加载时存在,不依赖任何实例,方法必须实现,不能用abstract修饰。
修饰代码块:在类加载完之后执行代码块的内容。
父类静态代码块->子类静态代码块->父类非静态代码块->父类构造方法—>子类非静态代码块->子类构造方法

final

1
2
3
4
5
6
修饰变量:
编译器常量:类加载是完成初始化,编译后带入到任何计算中,只能基本数据类型。
运行时常量:基本数据类型或引用数据类型,引用不可变,但引用的类型可变。
修饰方法:方法不能被继承,不能被子类修改。
修饰类:不能被继承。
修饰形参:final形参不可变。

15,HashMap和ConcurrentHashMap的区别
HashMap不是线程安全的,ConcurrentHashMap是线程安全的。
ConcurrentHashMap将整个Hash桶进行了分段segment,每个segment上面都有锁的存在。
ConcurrentHashMap的锁的粒度越细,并发性能越好。

16,线程安全
定义:类的行为与其的规范一致。
如何保证线程安全:
对变量使用validate
对程序进行加锁
17,多线程如何进行信息交互
Object中的方法,wait,notify(),notifyAll()

18,多线程共用一个变量需要注意什么
在线程对象runnable中定义了全局变量,run方法会修改该变量时,如果有多个线程同时使用该变量时候,可能有错误发生。
ThreadLocal是JDK引入的一种机制,它用于解决线程的共享变量,使用ThreadLocal声明的变量,即使在线程中属于全局变量,
针对每个线程来讲,这个变量是独立的。
validate变量每次被线程访问时,都会使得线程从主内存中重读该变量的最新值,而该变量发生修改时,也是把修改的值写入到
内存中去。

19,线程池
基本组成部分:
线程管理器(ThreadPool) :用户创建并管理线程池,包括创建,摧毁线程池,添加新任务。
工作线程(poolwork):线程池中的线程,在没有任务时,处于等待状态,可以循环使用。
任务接口(Task):每个任务必须实现的接口,以供工作线程调度的执行,它主要规定了任务的入口,
任务完成的收尾工作,任务的执行状态等。
任务队列(Taskqueue):用于存放没有处理的任务,提供一种缓存机制。

spring AOP 注解开发

1.简介

AOP主要包含了通知、切点和连接点等术语,介绍如下:

通知(advice)

通知定义了切面是什么以及何时调用,何时调用包含以下几种

1
2
3
4
5
Before 在方法被调用之前调用通知
After 在方法完成之后调用通知,无论方法执行是否成功
After-returning 在方法成功执行之后调用通知
After-throwing 在方法抛出异常后调用通知
Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

切点(PointCut)

通知定义了切面的什么和何时,切点定义了何处,切点的定义会匹配通知所要织入的一个或多个连接点,
我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。

连接点(JoinPoint)

连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,
切面代码可以利用这些连接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。

1
2
3
4
joinPoint.getSignature().getDeclaringTypeName() 可以获取到调用方法的类名(包括包名),
joinPoint.getSignature().getName() 可以获取方法名,
Arrays.toString(joinPoint.getArgs()) 得到的是方法调用的参数列表,
joinPoint.proceed() 可以得到方法的返回结果

2.注解开发

声明一个切面,只需要在类名上添加@Aspect属性即可,具体的连接点,我们用@Pointcut和@Before、@After等标注。
在声明前 我们需要依赖配置pom

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>

例子

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
package com.ganji.demo.service.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;
/**
* Created by admin on 2015/9/2.
*/
@Aspect
@Service
public class XmlAopDemoUserLog {
// 配置切点 及要传的参数
@Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)")
public void pointCut(int id)
{
}
// 配置连接点 方法开始执行时通知
@Before("pointCut(id)")
public void beforeLog(int id) {
System.out.println("开始执行前置通知 日志记录:"+id);
}
// 方法执行完后通知
@After("pointCut(id)")
public void afterLog(int id) {
System.out.println("开始执行后置通知 日志记录:"+id);
}
// 执行成功后通知
@AfterReturning("pointCut(id)")
public void afterReturningLog(int id) {
System.out.println("方法成功执行后通知 日志记录:"+id);
}
// 抛出异常后通知
@AfterThrowing("pointCut(id)")
public void afterThrowingLog(int id) {
System.out.println("方法抛出异常后执行通知 日志记录"+id);
}
// 环绕通知
@Around("pointCut(id)")
public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {
Object result = null;
try {
System.out.println("环绕通知开始 日志记录"+id);
long start = System.currentTimeMillis();
//有返回参数 则需返回值
result = joinpoint.proceed();
long end = System.currentTimeMillis();
System.out.println("总共执行时长" + (end - start) + " 毫秒");
System.out.println("环绕通知结束 日志记录");
} catch (Throwable t) {
System.out.println("出现错误");
}
return result;
}
}

AOP切面中的同步问题

在WebLogAspect切面中,分别通过doBefore和doAfterReturning两个独立函数实现了切点头部和切点返回后执行的内容,
若我们想统计请求的处理时间,就需要在doBefore处记录时间,并在doAfterReturning处通过当前时间与开始处记录的时间计算
得到请求处理的消耗时间。
那么我们是否可以在WebLogAspect切面中定义一个成员变量来给doBefore和doAfterReturning一起访问呢?是否会有同步问题呢?
的确,直接在这里定义基本类型会有同步问题,所以我们可以引入ThreadLocal对象,像下面这样进行记录:

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
@Aspect
@Component
public class WebLogAspect {
private Logger logger = Logger.getLogger(getClass());
ThreadLocal<Long> startTime = new ThreadLocal<>();
@Pointcut("execution(public * com.juzi.web..*.*(..))")
public void webLog(){}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis());
// 省略日志记录内容
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
}
}

AOP切面的优先级

由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对Web层做多个切面,校验用户,
校验头信息等等,这个时候经常会碰到切面的处理顺序问题。

所以,我们需要定义每个切面的优先级,我们需要@Order(i)注解来标识切面的优先级。i的值越小,优先级越高。
假设我们还有一个切面是CheckNameAspect用来校验name必须为didi,我们为其设置@Order(10),
而上文中WebLogAspect设置为@Order(5),所以WebLogAspect有更高的优先级,这个时候执行顺序是这样的:

在@Before中优先执行@Order(5)的内容,再执行@Order(10)的内容
在@After和@AfterReturning中优先执行@Order(10)的内容,再执行@Order(5)的内容
所以我们可以这样子总结:

在切入点前的操作,按order的值由小到大执行
在切入点后的操作,按order的值由大到小执行

Docker 应用

应用Docker部署

在项目的根目录下建立一个Dockerfile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM maven:3.3.3
ADD pom.xml /tmp/build/
RUN cd /tmp/build && mvn -q dependency:resolve
ADD src /tmp/build/src
#构建应用
RUN cd /tmp/build && mvn -q -DskipTests=true package \
#拷贝编译结果到指定目录
&& mv target/*.jar /app.jar \
#清理编译痕迹
&& cd / && rm -rf /tmp/build
VOLUME /tmp
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

因为 Spring Boot 框架打包的应用是一个包含依赖的 jar 文件,内嵌了 Tomcat 和 Jetty 支持,所以我们只需要使用包含 Java
的 Maven 镜像即可,不需要 Tomcat 镜像。
为了减少镜像大小,在执行 Maven 构建之后,清理了构建痕迹。
在 Dockerfile 文件的最后,使用 ENTRYPOINT 指令执行启动 Java 应用的操作。

构建 Docker 镜像

1
docker build -t docker-demo-spring-boot . //注意后面的 . 表示当前路径下

从镜像启动容器

1
docker run -d -p 8080:8080 docker-demo-spring-boot

完成部署:

URL访问,可通过docker ip查看应用的虚拟地址。

Docker Compose编排

Docker Compose是用于定义和组装运行多容器分布式应用的工具,
它提供一个简单的基于YAML语言的docker-compose.yml配置文件。 通常,我们使用docker定义和运行复杂的应用,
使用docker compose,在一个文件里定义多容器应用的启动顺序,起到服务编排的作用。

编写 docker-compose.yaml 文件

1
2
3
4
5
6
7
8
9
10
11
web:
build: .
ports:
- "8080:8080"
links:
- mongodb:mongodb
mongodb:
image: daocloud.io/library/mongo:latest
ports:
- "27017:27017"

这里以MongoDB数据库提供服务的demo,在该文件中,我们定于了两个服务:

基于我们应用构建的 docker-demo-java-mongo 镜像,用来提供 Web 服务
基于 DaoCloud 提供的 MongoDB 镜像,提供存储服务
通过 links 为 web 关联 mongo 服务

启动 Docker Compose

docker-compose up

spring Boot Cloud2

Spring Cloud介绍

Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务发现、断路器、
智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。

Spring Cloud与Dubbo对比

它们两都具备分布式服务治理相关的功能,都能够提供服务注册、发现、路由、负载均衡等。说到这,Dubbo的功能好像
也就这么多了,但是Spring Cloud是提供了一整套企业级分布式云应用的完美解决方案,能够结合Spring Boot,
Docker实现快速开发的目的,所以说Dubbo只有Spring Cloud的一部分RPC功能,而且也谈不上谁好谁坏。不过,
Dubbo项目现已停止了更新,淘宝内部由hsf替代dubbo,我想这会有更多人倾向Spring Cloud了。
从开发角度上说,Dubbo常与Spring、zookeeper结合,而且实现只是通过xml来配置服务地址、名称、端口,
代码的侵入性是很小的,相对Spring Cloud,它的实现需要类注解等,多少具有一定侵入性。

Spring Cloud子项目

1
2
3
Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),之前在第一章节也介绍这些,
比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud CloudFoundry、Spring Cloud AWS、
Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等项目。

配置服务

Spring Cloud通过Netflix OSS的Eureka来实现服务发现,服务发现的主要目的是为了让每个服务之间可以互相通信。
Eureka Server为微服务的注册中心。谈到Spring Cloud Netflix,它是Spring Cloud的子项目之一,主要提供的模块包括:
服务发现(Eureka),断路器(Hystrix),智能路由(Zuul),客户端负载均衡(Ribbon)等。
Spring Cloud使用注解的方式提供了Eureka服务端(@EnableEurekaServer)和客户端(@EnableEurekaClient)。

路由网关

路由网关的主要目的是为了让所有的微服务对外只有一个接口,我们只需访问一个网关地址,即可由网关将所有的请求代理
到不同的服务中。Spring Cloud是通过Zuul来实现的,支持自动路由映射到在Eureka Server上注册的服务。
Spring Cloud提供了注解@EnableZuulProxy来启用路由代理。

负载均衡

Spring Cloud提供了Ribbon和Feign作为客户端的负载均衡。在Spring Cloud下,使用Ribbon直接注入一个RestTemplate
对象即可,此RestTemplate已做好负载均衡的配置;而使用Feign只需定义个注解,有@FeignClient注解的接口,
然后使用@RequestMapping注解在方法上映射远程的REST服务,此方法也是做好了负载均衡配置。

路断器

断路器(Circuit Breaker)主要是为了解决当某个方法调用失败的时候,调用后备方法来替代失败的方法,
已达到容错/阻止级联错误的功能。Spring Cloud使用@EnableCircuitBreaker来启用断路器支持,
使用@HystrixCommand的fallbackMethod来指定后备方法。(@HystrixCommand(fallbackMethod=”fallbackOper”))
Spring Cloud还提供了一个控制台来监控断路器的运行情况,通过@EnableHystrixDashboard注解开启。

Spring Cloud依赖
spring_cloud

spring Boot Cloud 学习1

Spring 简介

Spring Project

Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作了。

Spring Boot:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署。

Spring Framework:即通常所说的spring 框架,是一个开源的Java/Java EE全功能栈应用程序框架,其它spring项目如spring boot也依赖于此框架。

Spring Cloud:微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。

Spring XD:是一种运行时环境(服务器软件,非开发框架),组合spring技术,如spring batch、spring boot、spring data,采集大数据并处理。

Spring Data:是一个数据访问及操作的工具包,封装了很多种数据及数据库的访问相关技术,包括:jdbc、Redis、MongoDB、Neo4j等。

Spring Batch:批处理框架,或说是批量任务执行管理器,功能包括任务调度、日志记录/跟踪等。

Spring Security:是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。

Spring Integration:面向企业应用集成(EAI/ESB)的编程框架,支持的通信方式包括HTTP、FTP、TCP/UDP、JMS、RabbitMQ、Email等。

Spring Social:一组工具包,一组连接社交服务API,如Twitter、Facebook、LinkedIn、GitHub等,有几十个。

Spring AMQP:消息队列操作的工具包,主要是封装了RabbitMQ的操作。

Spring HATEOAS:是一个用于支持实现超文本驱动的 REST Web 服务的开发库。

Spring Mobile:是Spring MVC的扩展,用来简化手机上的Web应用开发。

Spring for Android:是Spring框架的一个扩展,其主要目的在乎简化Android本地应用的开发,提供RestTemplate来访问Rest服务。

Spring Web Flow:目标是成为管理Web应用页面流程的最佳方案,将页面跳转流程单独管理,并可配置。

Spring LDAP:是一个用于操作LDAP的Java工具包,基于Spring的JdbcTemplate模式,简化LDAP访问。

Spring Session:session管理的开发工具包,让你可以把session保存到redis等,进行集群化session管理。

Spring Web Services:是基于Spring的Web服务框架,提供SOAP服务开发,允许通过多种方式创建Web服务。

Spring Shell:提供交互式的Shell可让你使用简单的基于Spring的编程模型来开发命令,比如Spring Roo命令。

Spring Roo:是一种Spring开发的辅助工具,使用命令行操作来生成自动化项目,操作非常类似于Rails。

Spring Scala:为Scala语言编程提供的spring框架的封装(新的编程语言,Java平台的Scala于2003年底/2004年初发布)。

Spring BlazeDS Integration:一个开发RIA工具包,可以集成Adobe Flex、BlazeDS、Spring以及Java技术创建RIA。

Spring Loaded:用于实现java程序和web应用的热部署的开源工具。

Spring REST Shell:可以调用Rest服务的命令行工具,敲命令行操作Rest服务。

Read More