ImportNew 笔记

这篇博客用来记录自己阅读 ImportNew 公众帐号文章的笔记.

2015-8-26:《关于 hashCode() 你需要了解的3件事》

  • 在一个运行的进程中, 相等的对象必须要有相同的哈希码, 如果你要重写 equals() 方法, 一定要同时实现 hashCode() 方法.
  • 但这并 不意味 有相同哈希码的对象一定相等 或者 不相等的对象的哈希码一定不相等.
  • 两个不同对象拥有相同哈希码称之为冲突. 冲突意味着有多个对象在同一个哈希空间里, HashMap 会再次检查以便来找到正确的对象. 会降低系统性能, 但是不会导致错误结果.
  • 不可使用哈希码作为 key 值.
  • 哈希码是可变的.
  • 在分布式应用中不要使用哈希码.

2015-8-27:《危险! 在 HashMap 中将可变对象用作 Key》

  • 可变对象是指当对象的状态(属性值等)发生变化之后, 它的哈希值会发生变化的对象.
  • HashMap 用 Key 的哈希值来存储和查找键值对.
  • 使用可变对象作为 HashMap 的 Key 值会造成数据丢失(以及内存无法回收).
  • 对象不可变的类包括基本数据类型, String 等.
  • 自定义不可变数据类型: 重写 hashCode() 方法, 用一个不可变的属性作为哈希值计算的唯一参数.

2015-8-28: 《Java 程序优化:字符串操作、基本运算方法等优化策略》– 字符串优化

String 有三个基本特点:

  1. 不变性: String 对象生成之后就不能再对其进行更改. 属于 “不变(immutable)模式”. 当一个对象需要多线程访问, 并且访问频繁时, 可以省略同步和锁等待的时间, 从而大幅提高系统性能.
  2. 针对常量池优化: 当两个 String 对象拥有相同的值时, 它们只引用常量池里的同一个拷贝, 当一个字符串反复出现时, 可以大幅节省内存.
    String str1 = "abc" String str2 = "abc" String str3 = new String("abc"); 其中 str1, str2 都引用了相同的地址, 它们是等同的. str3 却重新开辟了一块内存空间. 但即使如此 str3 所指向的实体(str3.intern())完全一样.
  3. 类的 final 定义: 这个类的定义是被 final 修饰的, 它不能被继承.

SubString 技巧

String 类的 subString() 方法内部, 最后执行会新建一个 String 对象, new String(offset + beginIndex, endIndex - beginIndex, value); . 这样做可以 重复使用母串的数组 , 但是如果我们只是想得到母串中的很小一段, 母串又很长, 那结果就是, 我们只想要很小一段字符串, 但是不得不持有整个母串的数组. 这样会 使大量的内存被占用而不能回收 . 建议做法 new String(str.subString(begin, end));, 这样, 母串就可以在之后的内存回收时被回收掉了.

切割字符串

实现方法:
1. String.split() 方法.
2. StringTokenizer 工具类.
3. 自己实现, 通过组合使用 subString()indexOf() 方法.

示例代码中母串很长, split() 方法耗时很大, 而 StringTokenizer 耗时很短. 实例运行结果差异较大的原因是 split 算法对每一个字符进行了对比,这样当字符串较大时,需要把整个字符串读入内存,逐一查找,找到符合条件的字符,这样做较为耗时。而 StringTokenizer 类允许一个应用程序进入一个令牌(tokens),StringTokenizer 类的对象在内部已经标识化的字符串中维持了当前位置。一些操作使得在现有位置上的字符串提前得到处理。 一个令牌的值是由获得其曾经创建 StringTokenizer 类对象的字串所返回的。

字符串合并

String 是不可变对象, 在需要修改字符串的时候都会创建新的字符串, 因此性能较差. 但是 JVM 会对代码优化, 将多个连接操作在编译时合成一个单独的长串.

字符串合并的实现方法: (效率是递增的)
1. 使用加号连接(+).
2. 使用 String.concat() 方法.
3. 使用 StringBuilder / StringBuffer.

StringBufferStringBuilder 的区别在于 StringBuffer 几乎对所有方法都做了同步, 同步会消耗系统资源, 所以 StringBuilder 效率相对较高; 但是在需要线程同步时, 要么自己做同步, 要么乖乖使用 StringBuffer.

补2015-8-29: 《Java 程序优化:字符串操作、基本运算方法等优化策略》– 数据定义/运算逻辑优化

这里写图片描述

使用局部变量

调用方法时, 方法参数 以及 局部变量 保存在栈(Stack)中, 读写速度较快. 其他变量, 如静态变量, 实例变量等在堆(Heap)中, 读写较慢.

位运算代替乘除法

位运算是所有运算中最高效的.

使用数组 + if-else 替换 switch 语句

在下面的两个方法中, 后者运行时间是前者的一半.

public int switchTest(int value) {
    int i = value % 10 + 1;
    switch(i) {
        case 1: return 10;
        case 2: return 11;
        case 3: return 12;
        case 4: return 13:
        case 5: return 14;
        case 6: return 15;
        case 7: return 16;
        case 8: return 17;
        case 9: return 18;
        default: return -1;
    }
}

public int arrayTest(int key) {
    int[] values = new int[] {0, 10, 11, 12, 13, 14, 15, 16, 17, 18};

    int i = key % 10 + 1;
    if(i > 9 || i < 1) {
        return -1;
    } else {
        return value[i];
    }
}

一维数组代替二维数组

一维数组的访问速度优于二维数组.

提取表达式

将重复的表达式提取出来:

// 将
double b1 = a1*a2*a3/3*4*a3*a4;
double b2 = a1*a2*a4/3*4*a3*a4;
// 改为:
double combine = a1*a2/3*4*a3*a4;
double b1 = combine*a3;
double b2 = combine*a4;

优化循环

  • 减少循环次数
  • 将重复的操作提取到循环外面

布尔运算代替位运算

在判断语句中, 使用布尔运算而不是位运算, 因为 Java 会对布尔运算做相当充分的优化

// 只要 a 是 true, 就不会判断 b 和 c
if(a || b || c){}
// 不论 abc 的值是什么, 都会执行两次位运算
if(a | b | c){}

使用arrayCopy()

System.arrayCopy() 是 JDK 提供的高效数据复制方法, 它是一个 native 方法, ArrayList 和 Vector 中大量使用这个方法来进行数据操作.

2015-9-23: 《细话 Java: “失效”的 private 修饰符》

private 修饰的成员是不可以被外部访问的, 但是, 当你定义一个内部类的时候, 会发现在外部类中可以访问到内部类的 private 成员, 而在内部类也同样可以访问到外部类的 private 成员, private 修饰符失效了吗?

并没有, 实际上在调用时是通过间接的方法来获取私有属性的。

同时, Java 内部类在构造时会持有外部类的引用, 这与C++不同

待续…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值