zeewane


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索
close

Project facet Java version 1.8 is not support

发表于 2016-08-12   |   分类于 BUG   |  

在移植eclipse项目时,如果遇到

“Project facet Java version 1.7 is not supported.”

项目中的jdk1.7不支持。说明项目是其他版本jdk编译的,在eclipse里运行时会报版本不支持。
解决办法:

  1. 选中项目 Properties , 选择 Project Facets,右击选择 Java , Change Version 即可

  2. 在项目的目录下有一个.settings的文件夹,该文件夹下有一个org.eclipse.wst.common.project.facet.core.xml文件,内容如下

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="UTF-8"?>
    <faceted-project>
    <fixed facet="jst.java"/>
    <fixed facet="jst.web"/>
    <installed facet="jst.web" version="2.4"/>
    <installed facet="jst.java" version="6.0"/>
    </faceted-project>

修改 <installed facet="jst.java" version="6.0"/> 为 <installed facet="jst.java" version="5.0"/> 即可。

直接用第一种方法改简单。

转载原文

shiro系列2-权限管理解决方案

发表于 2016-08-10   |   分类于 框架   |  

什么是粗粒度和细粒度权限

  • 粗颗粒度权限管理,是对资源类型的权限管理。
    资源类型比如:菜单、url链接、用户添加页面、页面信息、类方法、页面中按钮…
    粗粒度权限管理比如:超级管理员可以访问户添加页面、用户信息等全部页面。
    部门管理员可以访问用户信息页面包括 页面中所有按钮。

  • 细颗粒度权限管理,是对资源实例的权限管理。
    比如,员工号为001的修改链接,研发中心的用户信息,研发中心的员工…
    说的简单点,细粒度的权限管理,就是数据级别的权限管理。
    细粒度权限管理比如:部门经理只可以访问本部门的员工信息,用户只可以看到自己的菜单,大区经理只能查看本辖区的销售订单。

如何实现粗粒度和细粒度权限

粗颗粒度权限管理

粗粒度权限管理比较容易将权限管理的代码抽取出来在系统架构级别统一处理。比如:通过springmvc的拦截器实现授权。

细颗粒度权限管理

对细粒度权限管理在数据级别是没有共性可言,针对细粒度权限管理就是系统业务逻辑的一部分,如果在业务层去处理相对比较简单,就在service层处理的时候,传个部门id进去进行判断。如果将细粒度权限管理统一在系统架构级别去抽取,比较困难,即使抽取的功能可能也存在扩展不强。
建议细粒度的权限控制放在业务层去实现。
比如:部门经理只查询本部门员工信息,在service接口提供一个部门id的参数,controller中根据当前用户的信息得到该用户属于哪个部门,调用service时将部门id传入service,实现该用户只查询本部门的员工。

粗粒度和细粒度例子

系统有一个用户列表查询页面,对用户列表查询分权限,如果粗颗粒管理,张三和李四都有用户列表查询的权限,张三和李四都可以访问用户列表查询。
进一步进行细颗粒管理,张三(行政部)和李四(开发部)只可以查询自己本部门的用户信息。张三只能查看行政部 的用户信息,李四只能查看开发部门的用户信息。
细粒度权限管理就是数据级别的权限管理。

基于url拦截的方式实现

基于url拦截的方式实现在实际开发中比较常用的一种方式。
对于web系统,通过filter过虑器实现url拦截,也可以springmvc的拦截器实现基于url的拦截。

使用权限框架实现

对于粗粒度权限管理,建议使用优秀权限管理框架来实现,节省开发成功,提高开发效率。
shiro就是一个优秀权限管理框架。

shiro系列1-权限管理原理知识

发表于 2016-08-10   |   分类于 框架   |  

什么是权限管理

只要有用户参与的系统一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。

权限管理包括用户认证和授权两部分。

用户认证

概念

用户认证,用户去访问系统,系统要验证用户身份的合法性。最常用的用户身份验证的方法:1、用户名密码方式、2、指纹打卡机、3、基于证书验证方法等等。系统验证用户身份合法,用户方可访问系统的资源。

关键对象

  • subject
    主体,理解为用户,可能是程序,都要去访问系统的资源,系统需要对subject进行身份认证。
  • principal
    身份信息,通常是唯一的,一个主体还有多个身份信息,但是都有一个主身份信息(primary principal)。
  • credential
    凭证信息,可以是密码 、证书、指纹。

主体在进行身份认证的时候需要提供身份认证信息和凭证信息。

用户授权

概念

用户授权,简单理解为访问控制,在用户认证通过后,系统对用户访问资源进行控制,用户具有资源的访问权限方可访问。

通俗一点,就是你能不能够登陆是一回事,你登陆了能不能访问这些资源是另外一回事。前者叫访问控制,后者叫用户授权。
注册了以后你拥有了访问系统和系统资源的权限,之后系统还会继续进行资源访问的权限分配,这个决定你能访问具体哪些系统的资源。

关键对象

授权的过程可以理解为:who要对what(which)进行how操作

  • who:主体即subject
    subject在认证通过后进行访问控制。
  • what(which):资源(resource)
    subject必须具备资源的访问权限,方可访问该资源。资源比如,系统用户的列表页面、商品的修改菜单、商品id为001的商品信息,资源都是名词。
  • how:权限/许可(permission)
    针对资源的权限或许可,subject必须具有permission才可以访问资源,如何访问/操作需要定义permission,比如用户的添加、用户的修改、商品的删除,都是动词。

资源分为资源类型和资源实例,关系类似于类和对象。

  • 资源类型
    • 系统的用户信息
  • 资源实例
    • 系统中id为001的用户

权限模型

  • 主体(账号、密码)
  • 资源(资源名称、访问地址)
  • 权限(权限名称、资源id)
  • 角色(角色名称)
  • 角色和权限关系(角色id、权限id)
  • 主体和角色关系(主体id、角色id)

把下面的两张表合并,合并为权限表。
权限(权限名称、资源名称、资源访问地址)

分配权限

  • 用户需要分配相应的权限才可访问相应的资源。权限是对于资源的操作许可。
  • 通常给用户分配资源权限需要将权限信息持久化,比如存储在关系数据库中。
  • 把用户信息、权限管理、用户分配的权限信息写到数据库(权限数据模型)

权限控制(授权核心)

基于角色的访问控制

RBAC(Role Bssed Access Control),基于角色的访问控制。
比如 系统角色包括 :部门经理、总经理等等(角色针对用户来划分)

系统代码中实现:

1
2
3
4
5
//如果该user是部门经理则可以访问if中的代码
if(user.hasRole('部门经理')){
//系统资源内容
//用户报表查看
}

问题
角色针对人划分的,人作为用户在系统中属于活动内容,如果该 角色可以访问的资源出现变更,需要修改你的代码了,比如:需要变更为部门经理和总经理都可以进行用户报表查看,代码改为:

1
2
3
4
if(user.hasRole('部门经理') || user.hasRole('总经理')){
//系统资源内容
//用户报表查看
}

基于角色的访问控制,不利于系统维护,可扩展性不强。

基于资源的访问控制

RBAC(Resource Based Access Control),基于资源的访问控制。
资源在系统中是不变的。对资源的访问需要具有permission权限。

1
2
3
4
if(user.hasPermission('用户报表查看')){
//系统资源内容
//用户报表查看
}

这种方式可以解决用户权限变更,不用修改权限控制的代码。
需要变更权限,只需要去分配权限模块,给那些用户去分配相应的权限即可。

建议使用,基于资源的访问控制,来完成权限管理工作。

shiro系列3-Shiro简介

发表于 2016-08-09   |   分类于 框架   |  

什么是shiro

Apache Shiro一个功能强大,使用简单的Java安全框架,它为开发人员提供一个直观而全面的认证,授权,加密及会话管理的解决方案。

功能

实际上,Shiro的主要功能是管理应用程序中与安全相关的全部,同时尽可能支持多种实现方法。Shiro是建立在完善的接口驱动设计和面向对象原则之上的,支持各种自定义行为。Shiro提供的默认实现,使其能完成与其他安全框架同样的功能。

功能点描述:

  1. 身份认证/登录,验证用户是不是拥有相应的身份;
  2. 授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
  3. 会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
  4. 加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
  5. Web支持,可以非常容易的集成到Web环境;
    Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
  6. shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  7. 提供测试支持;
  8. 允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  9. 记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

官网使用手册

发展历程

Shiro最早的名字是JSecurity,后来更名为Shiro并成为Apache的孵化项目。现在的版本到了1.3.0

Spring Security

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI: Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

对比:

  1. Shiro is much easier to use , implement and most importantly understand than Spring
  2. The only reason Spring Security is much more well-known is because of the brand name “Spring” which is famous for simplicity , but ironically many find installing Spring Security little difficult
  3. Spring Security , however has a better community support
  4. Apache Shiro has an additional module over Spring Security of handling Cryptography

shiro的优势

  • Spring Security和spring依赖过于紧密,而且使用没有shiro来的简单。
  • shiro不依赖与spring
  • shiro不仅可以实现web应用的权限管理,还可以实现C/S系统、分布式系统权限管理
  • shiro属于比较轻量,越来越多的企业中也在使用shiro

shiro的架构

shiro架构

  • subject
    主体
  • securityManager
    安全管理器,主体访问和授权都是通过securityManager来进行,这是一个很大的容器?里面有很多的模块来实现相应的功能
  • authenticator
    认证器,主体进行认证最终通过authenticator来进行的
  • authorizer
    授权器,主体进行授权最终通过authorizer来进行
  • sessionManager
    web应用中,一般用中间件web容器对session进行管理。shiro自己也提供了一套session管理的方式。
  • sessionDAO
    通过sessionDAO来管理session数据,针对个性化的session数据存储,需要用到sessionDAO
  • catchManager
    缓存管理器,主要对session数据和授权数据进行缓存,比如将授权数据通过sessionManager进行缓存管理,和ehcache进行整合。管理的只是业务逻辑,真正的缓存操作还是要靠其他的框架来做。
  • Realm(领域)
    相当于数据源,通过realm来存取认证、授权的相关数据。
    在realm中存在授权和认证的逻辑。
  • cryptography
    密钥、密码,就是一个安全加密的方法,提供了一套加密和解密的组件以供开发。比如md5散列算法,没办法解密

开始使用shiro

下载

  • JDK 1.7.0_79
  • Maven 3.0.3
  • Tomcat 7.0.39
  • Shiro 1.3.0

运行

  • 解压源代码
1
2
3
4
$ cd shiro-root-1.3.0\samples\quickstart
// 执行java中的main函数
$ mvn compile exec:java

Subject

Subject 表示某一项(如一个人)的一组相关信息。此类信息包括 Subject 的身份,以及与安全相关的属性(例如,密码和加密密钥)。

Subject 可以潜在地具有多重身份。每个身份被表示为 Subject 中的一个 Principal。Principal 只是把名称绑定到 Subject。例如,Subject 正好是一个人(Alice)时,它可以有两个主体:一个把她驾驶证上的名称 “Alice Bar” 绑定到 Subject,另一个把学生身份证上的号码 “999-99-9999” 绑定到 Subject。即使每个主体具有不同的名称,它们也都指的是同一个 Subject。

Subject 也可以拥有与安全相关的属性,它们被称为证书。敏感的证书需要特殊的保护,例如私有加密密钥存储在私有的证书 Set 中。将证书设计为共享的,例如公钥证书或 Kerberos 服务票据存储在一个公开证书 Set 中。访问和修改不同的证书 Set 需要不同的权限。

Quickstart.java

Quickstart.java中包含刚刚提到的所有内容(认证、授权等等),通过这个简单的示例可以熟悉Shiro的API。

首先,几乎所有的环境下,都可以通过这种方式获取当前用户:

1
2
// get the currently executing user:
Subject currentUser = SecurityUtils.getSubject();

通过SecurityUtils.getSubject(),就可以获取当前Subject。Subject是应用中用户的一个特定安全的缩影,虽然感觉上直接使用User会更贴切,但是实际上它的意义远远超过了User。而且每个应用程序都会有自己的用户以及框架,我们可不想和它们混淆在一起,况且Subject就是安全领域公认的名词。

在单应用系统中,调用getSubject()会返回一个Subject,它是位于应用程序中特定位置的用户信息;在服务器中运行的情况下(比如web应用),getSubject会返回一个位于当前线程或请求中的用户信息。 现在你已经得到了Subject对象,那么用它可以做什么呢?

session

如果你想得到应用中用户当前Session的其他参数,可以这样获取Session对象:

1
2
3
Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );

这个Session对象是Shiro中特有的对象,它和我们经常使用的HttpSession非常相似,但还提供了额外的东西,其中与HttpSession最大的不同就是Shiro中的Session不依赖HTTP环境(换句话说,可以在非HTTP 容器下运行)。

如果将Shiro部署在web应用程序中,那么这个Session就是基于HttpSession的。但是像QuickStart示例那样,在非web环境下使用,Shiro则默认使用EnterpriseSessionManagment。也就是说,不论在应用中的任何一层使用同样的API,却不需要考虑部署环境,这一优点为应用打开一个全新的世界,因为应用中要获取Session对象再也不用依赖于HttpSession或者EJB的会话Bean。而且任何客户端技术都可以共享session 数据。

现在你可以得到当前Subject和它的Session对象。那么我们如何验证比如角色和权限这些东西呢?

很简单,可以通过已得到的user对象进行验证。Subject对象代表当前用户,但是,谁才是当前用户呢?他们可是匿名用户啊。也就是说,必须登录才能获取到当前用户。没问题,这样就可以搞定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// let's login the current user so we can check against roles and permissions:
if (!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
// ... catch more exceptions here (maybe custom ones specific to your application?
catch (AuthenticationException ae) {
//unexpected condition? error?
}
}

登陆过程中的异常会被捕获,不同的异常有对应的处理方式,也可以直接反馈给用户,说登陆错误请重新登陆,不用处理异常,直接让他重新登陆。

DispatcherServlet前端控制器的配置

发表于 2016-08-08   |   分类于 框架   |  
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
<!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等)
如果不去配置,那么默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)
一般情况下都会指定路径,以后会有很多框架要放进来
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 这个有多种方式配置
第一种:*.action,访问以action结尾的DispatcherServlet进行解析
第二种:/,所有访问的地址都由DispatcherServlet来进行解析,对于静态的文件解析
使用此种方法可以实现RESTful风格的url
第三种:/*,这样配置不对,最终要转发到一个jsp页面时,仍然会用DispatcherServlet
来解析页面,不能根据jsp页面来找到Handler,会报错
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>

斐波那契数列

发表于 2016-08-04   |   分类于 基础   |  
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
package com.hundsun.netease;
/**
* Created by zeewane on 2016/8/4/0004.
*/
public class FibonacciDemo {
public static void main(String[] args) {
System.out.println(Fibonacci(39));
}
public static int Fibonacci(int n) {
int preNum = 1;
int prePreNum = 0;
int result = 0;
if (n == 0)
return 0;
if (n == 1)
return 1;
for (int i = 2; i <= n; i++) {
result = preNum + prePreNum;
prePreNum = preNum;
preNum = result;
}
return result;
}
}

用循环的方法去解决,不要用递归。

java形参和实参

发表于 2016-08-03   |   分类于 基础   |  
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
package com.hundsun;
/**
* Created by zeewane on 2016/8/2/0002.
*/
public class Parameter {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int a : arr) {
System.out.println(a);
}
change(arr);
for (int b : arr) {
System.out.println(b);
}
change2(arr[0]);
for (int c : arr) {
System.out.println(c);
}
}
public static void change(int[] ints) {
ints[0] = 10;
}
public static void change2(int a) {
a = 11;
}
}
//1,2,3,4,5
//10,2,3,4,5
//10,2,3,4,5

因为第一个change传入的是地址,是真的在数组上干活

哈夫曼树构造方法

发表于 2016-08-02   |   分类于 基础   |  

在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)
树和哈夫曼编码。哈夫曼编码是哈夫曼树的一个应用。哈夫曼编码应用广泛,如
JPEG中就应用了哈夫曼编码。

什么是哈夫曼树

首先介绍什么是哈夫曼树。哈夫曼树又称最优二叉树,
是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

编码步骤

  1. 对给定的n个权值{W1,W2,W3,…,Wi,…,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列。)
  2. 在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
  3. 从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
  4. 重复二和三两步,直到集合F中只有一棵二叉树为止。

简单的理解就是,假如我有A,B,C,D,E五个字符,出现的频率(即权值)分别为5,4,3,2,1,那么我们第一步先取两个最小权值作为左右子树构造一个新树,即取1,2构成新树,其结点为1+2=3,如图:
image
虚线为新生成的结点,第二步再把新生成的权值为3的结点放到剩下的集合中,所以集合变成{5,4,3,3},再根据第二步,取最小的两个权值构成新树,如图:
image
再依次建立哈夫曼树,如下图:
image
其中各个权值替换对应的字符即为下图:
image

所以各字符对应的编码为:A->11,B->10,C->00,D->011,E->010

霍夫曼编码是一种无前缀编码。解码时不会混淆。其主要应用在数据压缩,加密解密等场合。

以上原文

个人理解

  • 构造一个哈夫曼树,首先要把那些带权值的叶子节点从小到大排序
  • 挑出最小的两个,构成一个二叉树,小的在左边
  • 然后把这时候,这两个节点相加的出来的父节点的值,放入到刚才的那个带权值的数组中去,然后重复这个步骤,挑出一个最小的然后继续画?应该就是这样
  • 哈弗曼编码就是左边是0,右边是1,然后边数边写,从根节点开始往下走

TCP协议状态变迁

发表于 2016-08-02   |   分类于 基础   |  

image

全部状态

一共有11种,分为客户端独有、服务端独有和共有。

客户端

  • SYN_SENT
  • FIN_WAIT1
  • FIN_WAIT2
  • CLOSING
  • TIME_WAIT

服务端

  • LISTEN
  • SYN_RCVD
  • CLOSE_WAIT
  • LAST_ACK

共有

  • CLOSED
  • ESTABLISHED

状态变迁

建立连接时的状态变迁

一开始,建立连接之前服务器和客户端的状态都为CLOSED。服务器创建socket后开始监听,变为LISTEN状态。客户端请求建立连接,向服务器发送SYN报文,客户端的状态变为SYN_SENT。服务器收到客户端的报文后向客户端发送ACK和SYN报文,此时服务器的状态变为SYN_RCVD。然后,客户端收到ACK、SYN,就向服务器发送ACK,客户端状态变为ESTABLISHED,服务器收到客户端的ACK后也变为ESTABLISHED。此时,3次握手完成,连接建立!

断开连接时的状态变迁

由于tcp连接是全双工的,断开连接会比建立连接麻烦一点点。客户端先向服务器发送FIN报文,请求断开连接,其状态变为FIN_WAIT1。服务器收到FIN后向客户端发生ACK,服务器状态变为CLOSE_WAIT。客户端收到ACK后就进入FIN_WAIT2状态。此时连接已经断开了一半了。如果服务器还有数据要发送给客户端,就会继续发送。直到发完了,就发送FIN报文,此时服务器进入LAST_ACK状态。客户端收到服务器的FIN后,马上发送ACK给服务器,此时客户端进入TIME_WAIT状态,再过了2MSL长的时间后进入CLOSED状态。服务器收到客户端的ACK就进入CLOSED状态。

CLOSING状态

CLOSING状态表示客户端发生了FIN,但没有收到服务器的ACK,却收到了服务器的FIN。这种情况发生在服务器发送的ACK丢包的时候,因为网络传输有时会有意外。

java中的构造块代码和构造函数

发表于 2016-08-01   |   分类于 基础   |  

代码块

构造代码块中的代码也是在构造方法中执行的。在编译时的编译器看来会默认将构造代码块中的代码移动到构造方法中,并且移动到构造方法内容的前面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestCode {
public TestCode() {
System.out.println("构造方法");
}
{
System.out.println("代码块");
}
public static void main(String[] args) {
new TestCode();
}
}

相当于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestCode {
public TestCode() {
System.out.println("代码块");
System.out.println("构造方法");
}
public static void main(String[] args) {
new TestCode();
}
}
//构造块
//构造方法

校招题

那么去理解网易的那个题:

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
class X{
Y y = new Y();
public X(){
System.out.println("X");
}
}
class Y{
public Y(){
System.out.println("Y");
}
}
public class Z extends X{
Y y = new Y();
public Z(){
System.out.println("Z");
}
public static void main(String[] args) {
new Z();
}
}

思路

  1. 首先去new一个Z,但是Z继承了X,所以先要去执行X的构造函数
  2. 发现X中有构造代码块和构造函数,所以先要去执行构造代码块,也就是new Y()
  3. 打印一个Y
  4. 然后继续执行X的构造函数,打印一个X
  5. 执行完Z的父类的new后,开始执行Z自己本身的new过程
  6. 发现Z中也有构造代码块,所以要先去执行构造代码块new Y(),再次打印一个Y
  7. 然后执行Z的构造函数,打印一个Z
  8. 最后的结果是YXYZ

静态代码块

  1. 父类的静态成员赋值和静态块 (静态块和静态成员的顺序为,谁在前面谁先执行(在不出错的情况下)
  2. 子类的静态成员和静态块
  3. 父类的构造方法
  4. 父类的成员赋值和初始化块
  5. 父类的构造方法中的其它语句
  6. 子类的成员赋值和初始化块
  7. 子类的构造方法中的其它语句
1234
戚志伟

戚志伟

To be a better man.

36 日志
9 分类
29 标签
RSS
知乎 微博 GitHub
© 2016 - 2017 戚志伟
由 Hexo 强力驱动
主题 - NexT.Pisces