Java核心技术(卷1)
一、基础概念
1.1 基本程序设计结构
-
1.1 数据类型
-
1.2 规范
-
1.2.1 变量
-
关于“$”
- 尽管$是一个合法的Java字符,但不要在自己的编码中使用这个字符,它只用在Java编译器或其他工具生成的名字中。
-
关于“++”的使用
- 建议不要在代码中使用“++”,这样的代码很容易让人困惑,而且会带来烦人的bug。
-
1.3 运算符
-
1.3.1 位运算符
-
和<<运算符将位模式左移或右移
-
运算符会用0填充高位;>> 会用符号位填充高位;不存在<<< 运算符;
- 位运算符的右操作数要完成模32的运算(除非左操作数是long类型,这种情况下需要对右操作数模64):1<<35 等于1<<3 等于8
-
1.3.2 运算符的级别
- &&的优先级比|| 的优先级高
- += 是右结合运算符,所以表达式: a+=b +=c 等价于: a+=(b+=c)
-
1.4 String
-
1.1 String是不可变字符串。一定不要使用“==”检测两个字符串是否相等,每次连接字符串,都会构建一个新的String对象;
每次连接都会创建一个新的字符串,这样既耗时,又浪费空间。使用StringBuilder类就可以避免这个问题的发生。
StringBuilder的前身是StringBuffer。StringBuffer效率稍微有些低,但允许采用多线程的方式执行添加或删除字符的操作。
StringBuilder 除了能够apped字符串,还能添加代码单元,添加码点
所有字符串都在一个单线程中编辑,则应该用StringBuilder代替它。
- 编译器可以让字符串共享。如果虚拟机使用让字符串共享就可以使用“==”运算符检测两个字符串是否相等。但,实际上只是字符串常量可以共享,而+或substring等操作产生的结果并不共享。
- “==”运算符能够用来确定两个字符串是否放在同一个位置。如果两个字符串放在同一个位置,它们必然相等。完全有可能将相同内容的字符串放在不同的位置上。
- 使用equals 方法比较两个字符串是否相等。
-
1.2 String 的length方法将返回采用UTF-16编码表示的给定字符所需要的代码单元数量
-
要想获取实际的字符长度,即码点数量,可以调用:codePointCount 方法
-
public static void test04() throws UnsupportedEncodingException {
String greeting = “Hello”;
String codeStr = “\uD835\uDD46”;
byte[] b = codeStr.getBytes(“UTF-16”);
String s = new String(b, “UTF-16”);
System.out.println(“greeting:”+greeting);
System.out.println(“一个UTF-16编码的特殊符号s:”+s);
System.out.println("greeting.length() : " + greeting.length()); // 打印出 5
System.out.println("greeting.codePointCount() : " + greeting.codePointCount(0, greeting.length())); // 打印出5
System.out.println("s.length() : " + s.length()); // 打印出 2
System.out.println("s.codePointCount() : " + s.codePointCount(0, s.length())); // 打印出 1
}
- greeting:Hello
一个UTF-16编码的特殊符号s:?
greeting.length() : 5
greeting.codePointCount() : 5
s.length() : 2
s.codePointCount() : 1
-
1.3 连接字符串:join 方法,可以指定分界符
-
1.4 所有字符串都属于CharSequence接口
-
1.5 控制流程
- “break 和 跳出标签”的用法:可以将标签应用到任何语句中,甚至可以应用到if语句或块语句中
-
1.6 数组
1.2 对象和类
-
修饰符:
-
final 实例域
- 可以将实例域声明为final,在构造对象的时候必出初始化这样的域;
- final修饰符大都应用于基本(primitive)类型域,或不可变(immutable)类的域。对于可变的类,使用final修饰可能会对读着造成混乱
- final 修饰的类不允许被继承;final修饰的方法不允许被覆盖;
- 如果将一个类声明为final,只有其中的方法自动地成为final,而不包括域;
-
static 方法
- 建议使用类名而不是对象名来调用静态方法,因为静态方法和对象没有任何关系。
- 静态方法的另一种常见用途是使用静态工厂方法来构造对象。
-
静态导入(import)
- import语句不仅可以导入类,还增加了导入静态方法和静态域的功能
-
其他
-
Java用于控制可见性的4个修饰符:
-
private 仅对本类可见;
-
public 对所有类可见;
-
protected 对本包和所有子类可见;
- 如果子类和父类不再同一个包下,应当用子类对象访问父类protected方法;
-
默认,不需要修饰符 对本包可见;
-
类的加载:
1.3 继承
-
继承是Java的核心技术
-
super和this
-
子类和超类
-
子类
-
子类构造器
- 使用super调用构造器的语句必须是子类构造器的第一条语句;
- 如果子类构造器没有显式调用超类构造器,将自动地调用该超类的默认构造器(没有参数的构造器)
- 如果子类构造器没有显式的调用超类构造器,超类又没有不带参数的构造器,Java编译器将报告错误
-
类型转化
- 只能在继承层次内进行类型转化;
- 在将超类转化为子类之前,应该使用instanceof进行检查;
- 只有在使用子类特有方法的时候才需要类型转换
- 一般情况下,应该尽量少用类型转换和instanceof运算符
-
多态和动态绑定
-
抽象类
-
多态:
- 一个引用类型的变量既可以引用当前类型的对象,也可以用子类型的对象;
-
动态绑定
-
覆盖
- 方法名字和参数列表称为方法的签名;
- 允许子类将覆盖方法的返回类型定义为原返回类型的子类型。称之为“协变返回类型”
-
Object
-
编写一个完美的equals方法
-
设计原则,equals方法要满足五个特性:
- 1、自反性;
- 2、对称性;
- 3、传递性;
- 4、一致性;
- 5、对于任意非空引用x,x.equals(null)方法应该返回false;
-
设计思路:
- 1、如果子类能够拥有自己的相等概念,则对称性要求将强制采用getClass进行检测;
- 2、如果超类决定相等的概念,那么就可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较。并应该将超类的equal方法声明为final;
-
完美的equals方法的建议:
-
1、显示参数命名为otherObject,稍后需要将它转换成另一个叫other的变量;
-
2、检测this域otherObject是否引用同一个对象:if (this == otherObject) return true;
-
3、检测otherObject 是否为null,如果为null,返回false: if (otherObjct == null) return false;
-
4、比较 this与otherObject 是否属于同一个类,如果equals的语义在每个子类中有所改变,就是用getClass检!= otherObject.getClass()) return false;
4、如果所有的子类都有统一的语义,就使用instanceof检测:
if (!(instanceof instanceof ClassName)) return false;
- Java为每个类型管理了一个Class对象。因此,可以利用 == 运算符实现两个类对象比较的操作。
- 5、将otherObject转化为相应的类型变量:
ClassName other = (ClassName) otherName;
- 6、现在开始对所有需要比较的域进行比较了。使用==比较基本类型域,使用equals比较对象域。所有的域都匹配返回true,否则返回false;
- 7、如果子类中重新定义equals,就要在其中包含调用super.equals(other)
- 如果重新定义equals方法,就必须重新定义hashCode方法
- toString方法
- 只要对象与一个字符串通过操作符“+”连接起来,Java编译器就会自动调用toString方法
- 在调用x.toString() 的地方可以用""+x替代
- println 方法就会直接调用x.toString() 并打印输出得到的字符串
- 强烈建议为自定义的每一个类增加toString方法
-
泛型数组列表ArrayList
-
ensureCapacity 方法
- 这个方法为数组列表分配一个初始容器,这样向数组列表中添加元素时,添加元素数量不大于初始化容器大小时,数组列表不用重新分配空间
-
trimToSize 方法
- 这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。垃圾回收器将回收多余的存储空间。
1.4 对象包装器和自动装箱
- 对象包装器是不可变的
- 装箱和拆箱是编译器认可的,而不是虚拟机
1.5 枚举类
二、Java的高级特性
2.1 反射
-
能够分析类能力的的程序称为反射
-
2.1.1 Class类
2.2 接口
-
基础概念:
- 接口的所有方法自动地属于public
- 接口中不能包含实例域或静态方法,但却可以包含常量。接口中的域将被自动设为public static final;
- 接口中的方法标记为public,接口中的域将被自动设为public static final。
Java语言规范建议不要书写这些多余的关键字。 - 每个类只能拥有一个超类,但却可以实现多个接口;
- 使用instanceof 检查一个对象是否属于某个特定类,也可以使用使用instanceof 检查一个对象是否实现了某个特定的接口
- 使用逗号将实现(implement) 的各个接口分隔开;
-
抽象类和接口
- 抽象类表示通用属性,有一个问题;每个类只能扩展于一个类;
- 接口可以提供多重继承的大多数好处,同时还能避免继承的复杂性和低效性。
-
新认识:
-
静态方法
public interface Path{
public static Path get(String first, String …more){
return FileSystem.getDefault().getPath(first,more);
}
}
- 在Java8中,允许在接口中增加静态方法。
- 通常是将静态方法放到伴随类中。在标准库中,可以看到成对出现的接口和实用工具类,如:
Collection/Collections - 以后在实现自己的接口时,不再需要为实用工具方法另外提供一个伴随类。
-
默认方法
public interface Comparable {
default int compareTo(T other){return 0;}
}
-
标记接口:
- 标记接口唯一的作用就是允许在类型检查中使用 instanceof
- 建议自己的程序中不要使用标记接口
-
函数式接口:只有一个抽象方法的接口
2.3 lambda表示式、方法引用、构造器引用
-
概要:
-
lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
-
函数式接口:只有一个抽象方法的接口
-
在java中,lambda表达式所能做的也只是能转换为函数式接口。
-
想要用lambda表达式做某些处理,还是要谨记表达式的用途,为它建立一个特定的函数式接口。
-
ArrayList类有一个removeIf方法,它的参数就是一个Predicate。这个接口专门用来传递lambda表达式。
- // 删除数组列表中为null的值
list.removeIf(e->e==null);
-
lambda 表达式的形式及组成:
-
lambda 表达式形式:参数,箭头(->)以及一个表达式
-
lambda有三部分构成:
- 1)一个代码块;
- 2)参数;
- 3)自由变量的值,这里指非参数而且不在代码中定义的变量;
-
代码块以及自由变量有一个术语,叫:闭包
-
lambda表达式可以捕获外围作用域中变量的值。但这里有一条规则:lambda表达式中捕获的变量必须实际上是最终变量。实际变量是指,这个变量初始化之后就不会再为它赋新值。
- lambda表达式中引用的变量值,既不能在lambda表达式中改变,也不应该在外部改变。
-
lambda中不能有同名的局部变量;
-
lambda 表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数。
- 例如:
public class Application(){
public void init(){
ActionListener listener = event -> {
System.out.println(this.toString());
}
}
}
这里的this指的是ActionListener
2.4 内部类
2.5 代理
2.6 Java的异常
}
- 无论这个块如何退出,in和out都会关闭
2.7 泛型程序设计
-
2.7.1 泛型类
-
2.7.2 泛型方法
- 例如:
public static getMiddle<T… a> - 类型变量放在修饰符后面,返回类型的前面;
-
2.7.2 类型变量的限定
-
例如:
public static T min(T[] a)…
-
一个类型变量使用通配符可以有多个限定:
T extends Comparable & Serializable
-
为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾
-
2.7.3 类型擦除
- 虚拟机没有泛型类型对象。
- 无论何时定义一个泛型类型,都自动提供了一个响应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)
- 为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾
-
2.7.4 通配符类型
-
2.7.5 无限定通配符
2.6 应用首选项的存储
三、图形程序设计
3.1 Swing
3.2 AWT
四、部署Java应用程序
4.1 Jar文件
-
4.1.1 创建Jar文件;
-
4.1.2 清单文件;
-
4.1.3 可执行Jar文件;
4.2 应用首选项的存储
五、集合
集合框架的接口
集合框架中的类
-
AbstractCollection
-
AbstractList
-
AbstractSet
-
AbstractQueue
-
AbstractMap
-
HashMap
-
TreeMap
-
EnumMap
-
WeakHashMap
-
IdentityHashMap
队列
链表
- 在Java程序设计语言中,所有链表实际上都是双向连接的。
- LinkedList对象根本不做任何缓存位置信息的操作。每次查找一个元素都要从列表的头部重新开始搜索。
- 使用链表的唯一理由是尽可能减少在列表中间插入或删除元素所付出的代价。
数组列表
散列集
树集
映射
视图与包装器
Properties
栈 Stack
位集 BitSet
- 由于位集将位包装在字节里。所以,使用位集要比使用Boolean对象的ArrayList更加高效。
- 案例:查找所有的素数
六、并发
线程
-
多进程和多线程的区别
- 本质区别在于每个进程拥有自己的一整套变量,而线程则共享数据
-
开启一个线程
-
方案一:实现Runnable接口
-
lambda方式
- Runnable r = ()->{System.out.println(“I have a dream.”);};
Thread t = new Thread®;
t.start();
-
内部类方式
- Thread t = new Thread(new Runnable(){
@Override
public void run() {
System.out.println(“This is inner class”);
}
});
t.start();
-
方案二:构建一个Thread类的子类
-
内部类方式
- new Thread(){
@Override
public void run() {
System.out.println(“I love you.”);
}
}.start();
-
继承的方案
- class MyThread extends Thread{
@Override
public void run() {
System.out.println(“This extend Thread”);
}
} - Thread thread = new MyThread();
thread.start();
中断线程
线程的状态
线程的属性
-
线程的优先级
- 在Java程序设计语言中,每一个线程有一个优先级
- 默认情况下,一个线程集成它父线程的优先级
- 可用setPriority方法提高或降低任何一个线程的优先级
- 每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。
- 线程优先级是高度依赖于系统的。不要将程序构建为功能的正确性依赖于优先级。
- static void yield() 导致当前执行线程处于让步状态
-
守护线程
-
守护线程的唯一用途是为其他线程提供服务。
- 例如:计时线程,它定时发送“计时嘀嗒”信号给其他线程或清空过时的高速缓存项的线程。
-
当只剩下守护线程时,虚拟机就退出了,由于如果只剩下守护线程,就没必要继续运行程序了。
-
守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。
-
setDaemon(boolean isDaemon),标记为守护线程,该方法必须在线程启动之前调用
-
未捕获异常处理器
同步
阻塞队列
阻塞队列就是线程安全的集合。
-
背景
- 对于实际编程应该尽量远离底层。
- 对于多线程问题,可以通过使用一个或多个队列以优雅且安全的方式将其形式化。
-
java.util.concurrent
-
使用
-
第一类
- 将队列当做线程管理工具来使用,put和take方法
-
第二类
- 当试图向满的队列中添加或从空的队列中移出元素时,add、remove和element操作会抛出异常
-
第三类
-
offer、poll、和peek方法
- 这些方法如果不能完成任务,只是给出一个错误提示而不会抛出异常。
线程安全的集合
-
高效的映射、集、队列
-
java.util.concurrent
- ConcurrentHashMap
- ConcurrentSkipListMap
- ConcurrentSkipListSet
- ConcurrentLinkedQueue
-
确定这样的集合当前的大小通常需要遍历
-
同步包装器
Runnable、Callable和Future
线程池
同步器
七、书籍推荐
看以下三本书籍,更有利于理解并发
-
《Java编程思想》
-
《Effective Java》
- D瓜哥:还可以看看中关于并发的描述
- 左耳朵狮子:如果C和OS基础不错,可以直接看effective java
-
现代操作系统 或 操作系统精髓
XMind: ZEN - Trial Version
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)