Jacendfeng

Jacendfeng 查看完整档案

杭州编辑西安电子科技大学  |  软件学院 编辑  |  填写所在公司/组织填写个人主网站
编辑

爱豆瓣,爱知乎,爱电影,KTV垃圾麦主,专注Java 服务器端开发,技术文章整理者。

个人动态

Jacendfeng 收藏了文章 · 2018-12-05

常见大数据和空间面试题

过滤100亿黑名单

题目

假设有100亿个URL的黑名单,每个URL最多占用64B,设计一个过滤系统,判断某条URL是否在黑名单里。

要求

不高于万分之一的判断失误率;额外内存不超过30GB

答案

100亿个64B的URL需要640GB的内存,显然直接存哈希表不合理。考虑布隆过滤器,假设有一个长度为m的bit类型数组,如图所示:

clipboard.png

输入阶段:

有k个哈希函数,函数的输出域S大于或等于m,假设哈希函数彼此独立,对于同一个输入(以字符串表示的URL),经过k个哈希函数的计算结果也是相互独立。对计算的每一个结果Mod m,将bit array上对应的位置置1,如下:

一个输入对象会将bitmap某些位置涂黑,处理完所有输入对象,会将bitmap相当多位置涂黑,至此,布隆过滤器生成完毕,代表之前所有输入对象的集合。

clipboard.png

20亿个数中出现最多的数

问题

包含20亿个全是32位整数的大文件,在其中找出出现次数最多的数。

要求

内存限制:2GB

答案

将20亿个数用hash函数分成16个文件。然后统计每个小文件中,哪个数字出现次数最多。最后再比较每个小文件的次数最多的数。(本题分成16个也是根据题目来的。考虑最极端情况。20亿个数都不同)32位的整数要占4b,key占4b,value占4b。共8b。内存只有2G。所以大概每个小文件存2亿条。就需要10个小文件。但是hash函数必须2的n次方。所以2的4次方。16个

40亿个数找没出现的数

问题

有一个包含40亿个无符号整数的文件,最多使用1GB内存,找到所有没出现的数

分析

最差情况,40亿个数都不同,哈希表保存出现过的数,需要内存4B*40亿,大约16GB内存。

答案

使用bitmap,申请一个长度为4294967295bit类型的bitArray,每个位置只表示0或1,该数组占用空间约500MB。遍历这20亿个数,例如遇到7000,就将bitArray[7000]置1。遍历完成后,再依次遍历bitArray,哪个位置没有置1,哪个数就不在40亿个数中。

40亿个数找第一个没出现的数 。内存只有10M

答案

具体的,第一次遍历,申请长度64的整形数组countArr[0...63],统计每个区间计数增加。例如,当前数是34225522090,34225522090/67108864=51,countArr[51]++。遍历完之后,必定有一个countArr[i]小于67108864,表示i区间内至少有一个数没出现过。此时countArr[]使用的内存是64*4B。

假设在37区间有一个数没出现,申请一个长度为67108864的bitmap,内存大约8MB,记为bitArr[0~67108863]。再一次遍历40亿个数,只关心37区间的数,记为num。将bitAry[num-6710886437]的值置位1。遍历完之后,bitArr必然有没有置1的位置,记为i,则6710886437+i就是没出现过的数。

找出100亿个重复URL以及搜索词汇topK问题

问题

有一个包含100亿URL的大文件,每个URL占64B,找出重复URL;补充,找出top100搜索词汇

常规答案

  1. 大文件通过哈希函数分配到不同机器
  2. 哈希函数将大文件拆分成小文件。

对于每一个小文件,利用哈希表遍历,找出重复的URL,或者分给机器或拆分文件完之后,进行排序,看是否有重复的URL。

补充问题的思路也是通过哈希函数分流,对于每个小文件,简历词频哈希表,建一个大小为100的小根堆,选出每个小文件的top100.每个小文件的top100进行外排序或者接着使用小根堆,就能得到100亿数据的top100.

出现两次的数以及中位数问题

问题

有40亿个无符号32位整数,最多可以使用1GB内存,找出所有出现了两次的数;补充问题,最多使用10MB内存,找到40亿个数的中位数

答案

第一个问题可以用bitmap做,申请长度为2?232bit的bitArr,2个bit表示一个数出现的词频。遍历40亿个数,假设出现num,将bitArr[2num]和bitArr[2num+1]设置为01,第二次出现,设置为10,第三次,设置为11。以后再遇到11的,就不做处理。遍历完成后,再遍历一次,若发现bitArr[2num]和bitArr[2num+1]是10,则num是出现了两次的数。

第二个问题,分区间讨论。长度为2MB的unsigned int数组占用8MB,将区间数目定位232/2M,取整为2148个区间,第0区间0~2M-1,第i区间2Mi~2M(i+1)-1

申请一个长度为2148的unsigned int整数数组arr[0..2147],arr[i]表示i区间有多少个数,arr占用内存小于10MB。遍历40亿个数,当前数num为num,落在区间(num/2M),对应arr[num/2M]++。累加统计每个区间的累计数目,就能找到40亿个数的中位数。例如0~K-1区间数目个数为19.998亿,加上第K个区间就超过了20亿,说要中位数一定在K区间中,并且一定是第K区间的第0.002亿个数。

接着申请长度2M的unsigned int数组countArr[0..2M-1],占用8MB。遍历40亿个数,只关心第K区间的数numi,countArr[numi-K*2M]++。统计完之后在第K区间找地0.002亿个数字即可。

一致性哈希

分布式数据库集群缓存,例如memcached,将数据的id通过哈希函数转换为key,假设有N个机器,计算key%N,得到及其所属编号,增删改查都在这台机器上。一致性哈希能在机器扩容(N发生变化),使得不用重新计算一遍key%N

三台机器处于哈希环,id通过哈希映射为key,在哈希环中顺时针找距离最近的机器。

机器较少的时候可能会出现负载不均衡,如图所示:

答案

引入虚拟节点,增加结点数

查看原文

Jacendfeng 评论了文章 · 2018-08-06

Linux 下执行定时任务 crontab 命令详解

许多内容抄录自自 竹子的博客

1、先来一个小小的例子

查看当前路径:

[root@root test]# pwd
/home/admin/test 
[root@root test]# crontab -l

查看当前用户的定时任务 也可以 crontab -uroot -l查看指定用户的定时任务。
千万不要忘了中间的 sh 表示用户拿什么来执行命令

00 02 * * * sh /home/admin/optbash/dailyBackup.sh
00 02 * * * sh /home/admin/optbash/deleteDebugSql.sh

建立一个用定时任务跑的bash脚本:

[root@root test]# touch test.sh
[root@root test]# vim test.sh

编辑如下内容,将系统当前时间输出到 console.txt 文件然后保存,增加可执行权限

/bin/echo `date` > /home/admin/test/console.txt
[root@root test]# ll
total 8
-rw-r--r-- 1 root root 29 Mar 27 21:31 console.txt
-rwxr-xr-x 1 root root 48 Mar 27 21:28 test.sh
[root@root test]# chmod +x ./test.sh

追加 crontab 定时任务,每分钟触发:

[root@root test]# crontab -e
00 02 * * * sh /home/admin/optbash/dailyBackup.sh
00 02 * * * sh /home/admin/optbash/deleteDebugSql.sh
*  *  * * * sh /home/admin/test/test.sh

前面是已经存在的定时任务,后面执行test.sh脚本的是追加的
保存后提示已经装载了新的定时任务

"/tmp/crontab.HauiiV" 3L, 143C written
crontab: installing new crontab

再次查看定时任务列表,可以看到定时任务已经添加

[root@root test]# crontab -l
00 02 * * * sh /home/admin/optbash/dailyBackup.sh
00 02 * * * sh /home/admin/optbash/deleteDebugSql.sh
*  *  * * * sh /home/admin/test/test.sh
[root@root test]# 

查看console.txt有没有每分钟写入console.txt文件

[root@root test]# vim console.txt
Fri Mar 27 21:40:01 EDT 2015 

可以看到最近一次的写入时间。

2、看看crontab 的时间表达式

基本格式 :
*  *  *  *  *  command
分 时 日 月 周 命令

图片描述

然后来几个实际的例子:

1、每分钟执行一次            
*  *  *  *  * 

2、每隔一小时执行一次        
00  *  *  *  * 
or
* */1 * * *  (/表示频率)

3、每小时的15和30分各执行一次 
15,45 * * * * (,表示并列)

4、在每天上午 8- 11时中间每小时 15 ,45分各执行一次
15,45 8-11 * * * command (-表示范围)

5、每个星期一的上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 command

6、每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * command

3、其他命令介绍

名称 : crontab

使用权限 : 所有使用者

使用方式 :

crontab file [-u user]-用指定的文件替代目前的crontab。

crontab-[-u user]-用标准输入替代目前的crontab.

crontab-1[user]-列出用户目前的crontab.

crontab-e[user]-编辑用户目前的crontab.

crontab-d[user]-删除用户目前的crontab.

crontab-c dir- 指定crontab的目录。 

4、crond 安装与配置服务

安装crontab:

yum install crontabs

服务操作说明:

/sbin/service crond start //启动服务

/sbin/service crond stop //关闭服务

/sbin/service crond restart //重启服务

/sbin/service crond reload //重新载入配置

查看crontab服务状态:

service crond status

手动启动crontab服务:

service crond start

查看crontab服务是否已设置为开机启动,执行命令:

ntsysv

加入开机自动启动:

chkconfig –level 35 crond on
查看原文

Jacendfeng 关注了用户 · 2018-03-23

死月 @xadillax

一個偽宅级别的蒟蒻碼畜。
Node.js Collaborator,造轮爱好者。
公众号:dmkoumakan(死月的红魔馆)

关注 199

Jacendfeng 发布了文章 · 2016-06-23

从Eclipse 到IDEA

起因

最近换工作,新公司用IDEA做开发,之前使用 win + Eclipse , 一下子切换到 mbp + IDEA 感觉很痛苦,手指完全不知落在什么键上。谨以此文做一个转变过程中的记录。

收集的一些比较好的学习文章:
IDEA官网从Eclipse 迁移到 IDEA
极客学院的一个教程

使用频率最高的快捷键

搜索

  • 全局搜索 shift * 2 (点两次shift键)

  • 类型搜索 command + O

  • 资源文件搜索 shift + command + O

  • 这个搜索会出现结果列表,啥都能搜 shirt + command + F

跳转

  • 转到定义(类型,方法) command + B

  • 转到实现 option + command + B

  • 后退前进 command + []

  • 找到下一个,指定文本后 command + G 反向则加 shirt

  • show in(将当前类在项目视图中展现) option + F1

修复

  • 代码格式化 option + command + L

  • 优化import ctrl + option + O

  • 删除当前行 command + delete

  • 快速定位错误 F2

  • 快速修复 option + enter

一些视图的展现

  • outline command + F12

  • 继承关系视图 ctrl + H

  • project视图 command + 1

  • 直接在里面使用终端 option + F12

  • 最大化当前窗口 shift + command + F12

编译,运行,Debug

  • 编译 command + F9

  • 运行 ctrl + R

  • 调试 ctrl + D

重构

  • 改名 shift + F6

  • 提取方法 option + command + m

  • 提取变量 option + command + v

操作撤销

  • 撤销 command + z

  • 恢复撤销 shift + command + z

查看原文

赞 0 收藏 9 评论 0

Jacendfeng 提出了问题 · 2016-04-25

解决segementFault 文章问题都打不开

技术团队帮忙解决下

图片描述

关注 2 回答 1

Jacendfeng 发布了文章 · 2016-04-01

Java 关键字专题

总览

Java 语言中有 50 个关键字,这些关键字不能用作标识符,如下图所示(来自 jls8)

图片描述

其中关键字 const 和 goto 是预留的,现在无法使用,并且在程序中出现会是编译器产生错误信息。

true 和 false 也许看起来像是关键字,但是他们专门用于表示布尔类型的字面量。类似的, null 专门用于表示 Null 类型的字面量。

其中 strictfp 始于 1.2,assert 始于 1.4, enum 始于 1.5, 这里说的都是 JDK 的版本。

下面我们先开始将关键词分类,无法的分类的关键词将分开讲解。

归类

基本类型

  1. char

  2. boolean

  3. doublefloat

  4. byteintlongshort

共计 8 中类型的基本类型,占据了 Java 的 8 的关键字。
下面简单介绍一下,从最简单的开始。

boolean

很简单,非真即假,有两个字面量,true 和 false。 值得注意的是,在 Java 中整形值和布尔值之间不能相互转换,至少在语言层面。网上有关 boolean 在内存中占用多大空间,这涉及到一个设计与实现的问题,Java 语言的规范和 Java 虚拟机的规范和最终实现的 Java 虚拟机的实现总会有实现上的语意偏离,而 Java 虚拟机的规范的原则也是在保证正确性的情况下尽量让虚拟机的实现提升效率。

相关的操作:

  1. == != 等于 不等于

  2. ! 取反

  3. & ^ | 位与 异或 或

  4. && || 条件与 条件或

  5. ? : 三目运算符

  6. 在控制流程中使用(if, while, do, for)

一个布尔值可且仅可被转型为 boolean, Boolean, Object 类型。

char

char 类型用于表示单个字符。
而关于 char 的长度是个非常有趣的问题,我们首先需要了解编码的相关知识。
可以看一下吴秦的博客,总结的很好。

在 Java 语言中字符编码是基于 Unicode 编码规范中的 UTF-16 实现的,UTF-16 具体定义了 Unicode 字符在计算机中的存取方法,UTF-16 使用定长的两个字节来表示 Unicode 的转换格式,也是16位长度,理论上可以表示
65536 个字符,然后在当时足够长的 char 类型在加入大量东亚体系的表意文字后, 16 位的 char 类型已经不能描述所有的 Unicode 字符了。

对此 Java 的对应策略可以参照 魏照哲的专栏 进行理解,学习完上面两篇博客和 Java 既有的字符表现形式,对于 char 长度这个问题大家应该要慎重对待。

byte short int long (Java 整型)

Java 的整型的范围是与机器无关的(这与 C,C++ 正好相反),因为 Java 程序时运行在 Java 虚拟机之上的,各个平台的上的 Java 虚拟机遵循同样的 Java 虚拟机规范。

这里再讲一些关于整型字面量表示的内容:

// 注意 '0' 是零 不是 字母 o 或 O
int a = 077;   // 前面加 '0' 表示八进制数, 十进制 63
int b = 0xee;  // 前面加 '0x' 或 '0X',后面的 ee 也可以表示成 EE、Ee、eE 表示十六进制,十进制238
int c = 0b00000001; // 前面加 '0b' 或 '0B',表示十六进制,十进制 1 ,JDK 1.7 增加的

另外顺便说下在整形字面量和浮点数中使用下划线的特性(也是JDK 1.7 增加的)

int a = 1_500_000; // 方便阅读
float b = 5_6.3_4;
// 需要注意的是不能以 '_' 开头,只能出现在数字中间,包括不能出现在进制标示的后面 '0x_EF' 这样不合法

float double

怎么说呢,它们无法精确的表示所有数,对于很多数而言,是存在误差的。
大家先看篇博客,我去喝杯咖啡

流程控制

  1. ifelseswitchcase

  2. whiledofor

  3. break用于退出 switch 和 当前循环,另外支持标签跳出多重循环

  4. continue用于结束本轮循环,从下轮循环开始执行

共计 9 个关键字。

关于流程控制关键字这里只讲一下 switch :
case: 标签可以是:

  1. char, byte, short, int, Character, Byte, Short, Integer

  2. enum 枚举类型

  3. String 字符串字面量 (JDK 1.7 增加),实际上是利用 hash 算法转化为 int 类型的语法糖

访问控制符

包括 public protected private

访问控制符决定了其他类是否可以使用特定的域或调用特定的方法。访问控制分为两个层次:

  • 顶层,可以修饰类,public, package-private (不需要显式修饰).

  • 成员层面,public, private, protected 或者 package-private (不需要显式修饰).

被声明为 public 的类对所有类可见,没有显式修饰的类只在包内可见。
关于成员的可见性,给出下图以供理解:
图片描述

包相关

  1. package

  2. import

包是我们用来分类相同功能模块的类、接口文件的一个集合,就像我们电脑中文件夹一样。声明在类或接口文件的头部,如下所示:
package packageName
关于包我们需要牢记的一点是,相同前缀的包除了可以在组织上在一起,但是实际上他们没有任何关系:
例如 com.sun.a 和 com.sun 作为两个包没有任何关系,属于独立的类集合。

既然包已经将我们类组织起来,那么我们如何来使用包中个类的?
我们可以像下面一样使用类的全限定名:

java.util.Date date = new java.util.Date(); 
// 假如你一直这么干,那么恭喜你,你对 JDK 中常用类分布一定非常熟悉
// 假如你一直这么干,并且使用黑轴的机械键盘,那么很不幸,你手指一定非常酸痛

这时 import 关键字就登场了,我们可以这样:

import java.util.Date;
...
Date date = new Date();

实际上在这里我必须要提前讲到 static 关键字,JDK 1.5 起支持静态导入:

// 让我们可以不同导入 Math 类再使用 PI 静态变量
import static java.lang.Math.PI;   
public  class MathUtils{   
    //计算圆面积   
    public static double calCircleArea(double r){   
        return PI * r * r;   
    }   
    //计算球面积   
    public static double calBallArea(double r){   
        return 4 * PI * r * r;   
    }   
}   

面向对象

对于各种编程范式,没有本质上的优劣,都是为了更好的解决问题而存在的,我们需要权衡利弊,简单就是一种美。
下面有几篇文章是关于面向对象一些内容,大家可以看看:
Wiki的词条 ------ 如何理解面向对象
代码重构的一个例子 -------- 各种流行的编程方式
有时候走得太远,我们都忘了我们为何出发,不忘初心,不仅对于梦想,对程序设计也是如此。

开始将涉及的关键字再次分类:

  1. class interface

  2. extends implements

  3. abstract static native

  4. new

  5. instanceof

  6. this super

  7. return

  8. void
    这部分内容涉及面太广,大家自己看看书吧,哈哈。

异常处理

五连发
try catch finally throw throws

并发与同步

三连发
finalvolatilesychronized
final 基础用法
内存模型系列文章 建议大家看完这一系列文章

什么鬼的其他

五连发
enum default assert strictfp transient

enum

先看用法----》源码解析---》一篇e文

default

在 switch 语句的的使用:

int i=3;
switch(i)
{
   case 1:
       System.out.println(1);
       break;
   case 2:
       System.out.println(2);
       break;
   case 3:
       System.out.println(3);
       break;
   default:
       System.out.println("default");
       break;
} 

在注解中的使用

不了解注解的朋友可以先看几篇文章Java 注解指导手册-----注解的实现-曹旭东的回答

关于 default 在注解中的使用
来自 Java Language Specification 8 9.6.2 章节
An annotation type element may have a default value, specified by following the
element's (empty) parameter list with the keyword default and an ElementValue

Default values are not compiled into annotations, but rather applied
dynamically at the time annotations are read. Thus, changing a default
value affects annotations even in classes that were compiled before
the change was made (presuming these annotations lack an explicit
value for the defaulted element)

public @interface RequestForEnhancementDefault {
    int id(); // No default - must be specified in each annotation
    String synopsis(); // No default - must be specified in each annotation
    String engineer() default "[unassigned]";
    String date() default "[unimplemented]";
}

interface default method (JDK 1.8)

我就不瞎比比了,大家看下几篇介绍文章:
天马流星拳------圆月弯刀

assert

在各种测试框架大行其道的背景,这个关键字的使用,应该仅限于简单的程序测试,需要注意的是断言机制是否生效需要的显式地指定 JVM 运行参数。参考 Programming With Assertions

strictfp

引用 stackoverflow 上的一个回答来终结这个关键字

It all began with a story,

When java was being developed by James Gosling, Herbert and rest of
his team. They had this crazy thing in mind called platformindependency.
They wanted to make oak(Java) so much better that it
would run exactly same on any machine having different instruction
set, even running different operating systems. But, there was a
problem with decimal point numbers also known as floating point and
double in programming languages. Some machines were built targeting
efficiency while rest were targeting accuracy. So, the later(more
accurate) machines had size of floating point as 80 bits while the
former(more efficient/faster) machines had 64 bit doubles. But, this
was against there core idea of building a platform independent

  1. Also, this might lead to loss of precision/data when a code

  2. built on some machine(having double of 64 bit size) and run on

another kind of machine(having double of 80 bit size).

Up-Sizing can be tolerated but Down-Sizing can't be. So, they came
across a concept of strictfp i.e. strict floating point. If you use
this keyword with a class/function then its floating point and doubles
have a consistent size over any machine. i.e. 32/64 -bit respectively.

transient

给出几篇文章来循序渐进地解决这个关键字
序列化用法--->深入分析序列化--->单独说下transient关键字---》序列化高级认知---》序列化中那些你不知道的5件事---》使用SealedObject & SignedObject对序列化加密解密(只需要关注SealedObject & SignedObject 加解密这部分)

查看原文

赞 0 收藏 4 评论 0

Jacendfeng 提出了问题 · 2016-03-25

Maven 工程 jetty 容器中使用 JRebel 报错

报错如下:

2016-03-25 16:37:17 JRebel: Class 'javax.xml.parsers.FactoryFinder' could not be processed by com.zeroturnaround.javarebel.yp@null
2016-03-25 16:37:17 JRebel: ERROR org.zeroturnaround.bundled.javassist.NotFoundException: find(..) is not found in javax.xml.parsers.FactoryFinder
    at org.zeroturnaround.bundled.javassist.CtClassType.getDeclaredMethod(JRebel:1229)
    at com.zeroturnaround.javarebel.yp.process(JRebel:16)
    at org.zeroturnaround.javarebel.integration.support.JavassistClassBytecodeProcessor.process(JRebel:62)
    at com.zeroturnaround.javarebel.java5.AgentInstall.a(JRebel:307)
    at com.zeroturnaround.javarebel.java5.AgentInstall.a(JRebel:135)
    at com.zeroturnaround.javarebel.java5.AgentInstall.premain(JRebel:98)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
    at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)

本人项目中除了 JDK7 中有这个类,maven依赖有两个相同的类,之前一直没有出现过问题,
本地工程使用 mvn jetty:run 命令来启动,
JRebel 的配置放在下图中
图片描述
我想请教在 mvn jetty:run 这种启动方式下面 JRebel classLoader 的加载路径,如果可以进一步帮忙解决这个问题就更好不过了。

关注 1 回答 0

Jacendfeng 提出了问题 · 2016-03-21

segmentfault 上面的标签是怎么设计的,包括我关注的标签等的设计

segmentfault 上面的标签是怎么设计的,包括我关注的标签等的设计,最近需要实现类似的功能,看大家能不能提供一些好的建议

关注 1 回答 0

Jacendfeng 发布了文章 · 2016-03-07

在Ubuntu 12.04 32位系统中编译OpenJDK 7u40

环境准备

我的编译环境的为Ubuntu 12.04 32位系统,双核

OpenJDK 源码

通过 Mercurial 代码管理工具下载太慢,这里选择直接下载官网源码包

Apache Ant

用于执行 Java 编译代码中的 Ant 脚本

Bootstrap JDK

编译 OpenJDK 需要一个可用的 JDK

安装依赖软件命令

打开终端,输入以下命令:

sudo apt-get install build-essential gawk m4 openjdk-6-jdk
libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev
x11proto-print-dev binutils libmotif3 libmotif-dev ant

如何找不到软件包,可以先执行以下命令:

sudo apt-get update

这个命令将会更新可用软件列表

解压JDK源码

将源码解压到 /home/jacend/Download/ 目录下面,大家可以自己选择一个合适的目录

unzip openjdk-7u40-fcs-src-b43-26_aug_2013,zip /home/jacend/Download/

解压后再 /home/jacend/Download/ 下面会出现一个 openjdk 的源码目录,该目录下包括了jdk,hotspot以及一些Java工具的源码

编译

创建一个安放编译结果的目录

我会将编译的结果放在 /home/jacend/pgSoft/openjdk_7u4/build

mkdir /home/jacend/pgSoft/openjdk_7u4
cd /home/jacend/pgSoft/openjdk_7u4
mkdir build

创建一个运行编译的脚本

我们将在解压的源码包中创建一个 build_open_jdk.sh 的脚本并且赋予执行权限

cd /home/jacend/Download/openjdk/
touch build_open_jdk.sh
sudo chmod +x build_open_jdk.sh

sudo gedit build_open_jdk.sh

脚本中输入以下内容

#语言选项
export LANG=C
## Bootstarp JDK 的安装路径,也就是我们安装的 openJDk 6 的根目录
export ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk-i386
#允许自动下载依赖
export ALLOW_DOWNLOADS=true

#并行编译的线程数,设置与CPU内核数量一致,我的笔记本为双核CPU,此项可以提高编译速度
export HOTSPOT_BUILD_JOBS=6
export ALT_PARALLEL_COMPILE_JOBS=6

export SKIP_COMPARE_IMAGES=true
#使用预编译头文件,不加这个编译会慢很多
export USE_PRECOMPLIED_HEADER=true

#要编译的内容
export BUILD_LANGTOOLS=true
export BUILD_HOTSPOT=true
export BUILD_JDK=true

#把它设置为 false 可以避开 javaws 和浏览器插件之类的部分的 build
BUILD_DEPLOY=false

#把它设置为 false 就不会 build 出安装包,因为安装包中有些奇怪的依赖
#但即便不build出它已经可以得到完成的JDK映像了,所以还是不 build 了
export BUILD_INSTALL=false

#编译结果所存在的路径
export ALT_OUTPUTDIR=/home/jacend/pgSoft/openjdk_7u4/build

#这两个编译变量必须去掉,不然编译会出问题
unset JAVA_HOME
unset CLASSPATH

#检查设置是否正确
make sanity
make 2>&1 |tee $ALT_OUTPUTDIR/build.log

执行脚本

cd /home/jacend/Download/openjdk/
sh ./build_open_jdk.sh

编译过程中的错误

列举一下编译过程的错误,供大家参考,大家可以预先处理了再执行编译脚本

  1. error: "__LEAF" redefined [-Werror]
    碰到这个错误可以 参考 在这个环境下应该不会报这个错误

  2. JVM_FindClassFromCaller
    修改文件:/home/jacend/Download/openjdk/hotspot/make/linux/Makefile 注释掉包含test_gamma字样的所有行即可

  3. Error: time is more than 10 years from present: 1104530400000

    进入解压后openJDk目录,找到CurencyData.properties,将所有涉及到时间修改为10年之内的时间,例如将2004-01-13-20-00-00 修改成 2016-01-13-20-00-00

    cd /home/jacend/Downloads/openjdk/jdk/src/share/classes/java/util
    sudo gedit CurrencyData.properties
查看原文

赞 0 收藏 0 评论 0

Jacendfeng 赞了回答 · 2016-03-03

解决Java 中 linkedList 类的没有按照Object类toString 方法输出

你说的这个是Object类的默认实现

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

实际上,LinkedList的toString()的输出是这样的

[111, 222, 333]

这是为啥呢?请看下图:
图片描述
从图中,可以看到,它的祖先类中有一个AbstractCollection
而在这个类中,有一个toString()的覆写:

public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

看到这里,应该理解了吧?

关注 4 回答 3

认证与成就

  • 获得 53 次点赞
  • 获得 27 枚徽章 获得 0 枚金徽章, 获得 12 枚银徽章, 获得 15 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2014-04-08
个人主页被 1k 人浏览