java核心技术(第十版卷一)笔记(纯干货!)
这是我读过的第三本关于java基础的书.第一本<<java从入门到精通>>这本书让我灵识初开.第二本<<java敏捷开发>>这本书则是有一次被一位师傅批评基础太差时读的.今日我向一位前辈请教应该怎样再进步一点.前辈推荐我读<<Java核心技术>>并告诉我,先读了这两本查漏补缺,然后在给我推荐进阶的书.工具书这种东西,每一本都不可能相同,比如我们的数学书,同样是小学的,两个地区的书可能就不同.
以下为这本java核心技术中所积累的知识,仅为记录笔记
--------------------------------------------------------------------------------------------------------
自动类型转换
两个数值.如果有double,则转换成double.否则有float,转换成float.否则有long,转换long.否则都转换成int
类之间的关系
依赖(uses-a):A类依赖B类.A类需要调用B类
聚合(has-a):A类包含B类.
继承(is-a):A类继承自B类.A类包含B类的属性行为,以及有自己的属性和行为
对于方法参数
其实是有一个隐藏的参数,就是this.表示当前的调用对象,而静态方法中,则不存在this.因为静态方法不依赖实例对象 final修饰类的原则
如果一个类的内部,没有提供可修改类本身状态的方法.则可将该类设为final(被final修饰的类不可以被继承,如果你继承了一个final类,则代表你可以自定义方法修改final类的属性,其破坏了封装性.这个坑在某个面试中,被坑了....
如果一个class被声明为final,那么其所有的方法也默认被设置为final,而字段则不在final中.被final修饰的类主要目的还是阻止其他类通过成为其子类的方式而修改本身类的行为.
java的参数统一是按照值传递的.基本数据类型传递的值的副本.引用数据类型传递的引用的副本,所以方法内部对参数进行的修改,不会影响实参.
public class Person {
public int age = 1;
}
public class Test {
public static void main(String[] args) {
int y = 1;
change(1);
System.out.println(y);//1
Person p = new Person();
change(p);
System.out.println(p.age);//2
change2(p);
System.out.println(p.age);//2
} public static void change(int x) {
x = 2;
} public static void change(Person p) {
p.age = 2;
} public static void change2(Person p) {
p = new Person();
p.age = 3;
}
}
以上例子可以看出当我们传递一个基本数据类型参数,方法中的改变不会更改原有的值.这个对于上边的法则是能对于的.但是我们传递一个引用类型得到实参,则有了令人产生歧义的结果.实际上,这个结果是很迷惑人的(起码在一段长的时间,我也没有真正搞懂上边规则的真正意思.)我们先来看change2()这个方法,这个方法内部,对传入的实参重新new了一个对象,也就是说,当前方法中的p已经被重新实例化了.所以,当你把新的实例化的对象中的属性域修改了值,那么根据以上的法则,当然不会影响main()方法的实参.再来看,change1()的内部构造,他直接将实参对象的一个属性域的值修改了,结果竟然映射到了,main()方法中.这岂不是有悖于以上法则?其实不然,我们可以追溯到基本数据类型,当一个int i = 1;被创建则 1 已经被分配了内存空间.我们我们将 i = 2 那么 i 只是换了一个应用值2,实际的1还是存在的(这里我们暂且不考虑垃圾回收)话题回来,我们在change()中修改了实参的一个属性,那么这个实参的实际存储地址变了吗?没有的.而change2()则是直接新建了一个对象,新开辟了一片内存,你在新的地址里更改自己的属性,当然也不会影响实参的属性.(ps关于这类的问题,我曾经看过很多形参,实参,传值,传址之类的博客,其实看得越多,越迷糊.如果你看到以上我的描述,觉得没有茅塞顿开那么就请忘掉他.避免对你造成更大的困扰)
关于构造函数
在一个类中,如果有成员 int i; 而改成员没有值.则会在new出该对象实例时,赋值为0;这个动作原来是在构造函数执行的.数值类型被默认为0,Boolean被默认为false,引用类型被默认为null.
equals特性
1 自反性: 对于任何非空引用x,x.equals(x);应当返回true.
2 对称性: 对于任何引用x和y,当且仅当y.equals(x);返回true,x.equals(y);也应当返回true.
3 传递性: 对于任何引用x,y,z如果x.equals(y)返回true; y.equals(z)返回true;那么x.equals(z);应当返回true
4 一致性: 如果x和y的引用对象没有发生变化,返回调用x.equals(y);应当返回同样的结果.
5 对于任意非空引用 x,x.equals(null);应当返回false.
关于包装类型Integer
对于包装类型我们大家都熟悉.对于以下操作我们则是使用了包装类型的特性:自动装箱.自动拆箱
public static void main(String[] args) {
Integer i = 100;
i = i + 1;
System.out.println(i);
}
这里有个对于自动装箱有个值得思考的问题,如果两个相同的数值用==判断,如果数值相同,则返回true.那么如果将这两个数值装箱为Integer还能用==判断吗?
public static void main(String[] args) {
Integer i = 1000;
Integer x = 1000;
System.out.println(i == x);//false Integer z = 100;
Integer y = 100;
System.out.println(z == y);//true
}
i 和 x 的==判断是我们意料之中的.两个对象 == 如果地址不同肯定是false嘛!那么 z 和 y呢?
书中的解释
自动装箱规范要求 boolean、byte、char 127, 介于 -128 ~ 127 之间的 short 和
int 被包装到固定的对象中。
但是需要注意的如果我们显式的创建两个Integer可不会有这个特性.
public static void main(String[] args) {
Integer i = 127;
Integer x = 127;
System.out.println(i == x);//true Integer z = new Integer(127);
Integer y = new Integer(127);
System.out.println(z == y);//false
}
另外这里还有一点.之前我们说,当向一个方法传递引用类型的实参时,我们是有可能修改这个实参的属性的.那么我们来看这个
public static void main(String[] args) {
Integer i = new Integer(1);
change(i);
System.out.println(i);//
} public static void change(Integer i) {
i = i.valueOf(2);
i = 3;
}
白日做梦~~~~怎么可能会让你修改一个基本类型的值呢.~~~~~
关于接口的默认方法
在JDK8中接口中可以提供默认的实现方法.如果,一个类的父类和接口有同样的一个方法.子类会选择使用谁的呢?
public class P1 {
public void add(){
System.out.println("");
}
}
public interface P2 {
default public void add(){
System.out.println("");
}
}
public interface P3 {
default public void add(){
System.out.println("");
}
}
public class Person extends P1 implements P2,P3{
public static void main(String[] args) {
Person p = new Person();
p.add();//
}
}
结果是继承优先.
那如果两个接口有同样的默认方法呢?
结果是报错.
public class Person implements P2{
public static void main(String[] args) {
P2.get();
}
}
接口的静态方法
此外jdk8还运行接口定义静态方法
public interface P2 {
public static void get(){
System.out.println("get");
}
}
public class Person implements P2{
public static void main(String[] args) {
P2.get();
}
}
我们可以直接使用接口 . 的方式使用静态方法.
但是一下调用是不可以的.
可以看出当一个父接口有静态方法时,子实现是没有继承父类的静态方法的.这一点和继承是不一样的.
我们来看下继承中的静态方法.
public class P1 {
public static void add(){
System.out.println("");
}
}
public class Person extends P1{
public static void main(String[] args) {
Person.add();
}
}
这两个的区别要搞清楚.
Comparable 和 Comparator
在我们使用一些工具类的sort排序方法时,比如Arrays或者Collections时他们总是需要我们将需要排序的类实现 Comparable 接口中的.compareTo().原因就是,假设要对一个集合中的User进行排序,那么您总要告诉工具类您要的排序规则是啥对吧.那么再来说说既然有了Comparable 为啥还要有Comparator这个接口.在面向对象的设计理念中,一个类,他最好只有属于自己特点功能的方法显然,排序这个方法,只能算是工具方法.所以在一个类的设计初期,非常可能的并没有实现Comparable 中的compareTo()方法.而在后期的开发业务功能时,我们发现,我们需要对User类进行排序呀.这时为了不破坏原有的代码,我们则可以另外创建一个类,并让这个类实现Comparator接口中的compare()方法.并在使用工具类时,将Comparator的实现类传递给工具类.这样的设计理念主要还是为了保证一个类的完整性,已经单一功能性.
关于clone
在Object中有一个方法clone()此方法是一个受保护的方法.clone().关于这个受保护的clone()方法在子类中不能直接使用的问题.PS必须实现Cloneable标记方法,而且您还要覆盖Objece类的clone()才能使用.至于为啥这个clone明明是受保护的类子类不能直接用,百度了好久,也没找到答案,本着不钻牛角尖的精神.咱们只来探究下clone()一起的浅拷贝深拷贝问题.
public class Test1 implements Cloneable{
public int age = 1;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Run {
public static void main(String[] args)throws Exception{
Test1 test1 = new Test1();
Test1 test11 = (Test1) test1.clone();
test11.age = 2;
System.out.println(test1.age);//
System.out.println(test11.age);//
}
}
结果是被拷贝的对象被改变了,不会影响原对象.这算是深拷贝.那咱们再来试试原对象中有引用类型,会怎样.
public class Test1 implements Cloneable{
public int age = 1;
public String name = "张三";
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Run {
public static void main(String[] args)throws Exception{
Test1 test1 = new Test1();
Test1 test11 = (Test1) test1.clone();
test11.age = 2;
test11.name="李四";
System.out.println(test1.age);//
System.out.println(test11.age);//
System.out.println(test1.name);//张三
System.out.println(test11.name);//李四
}
}
引用类型也会深拷贝.那咱们在来换个自定义的引用类型.
public class Person {
public int height; public Person(int height) {
this.height = height;
}
}
public class Test1 implements Cloneable{
public int age = 1;
public String name = "张三";
public Person person = new Person(1);
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Run {
public static void main(String[] args)throws Exception{
Test1 test1 = new Test1();
Test1 test11 = (Test1) test1.clone();
test11.age = 2;
test11.name="李四";
test11.person.height = 3;
System.out.println(test1.age);//
System.out.println(test11.age);//
System.out.println(test1.name);//张三
System.out.println(test11.name);//李四
System.out.println(test1.person.height);//
System.out.println(test11.person.height);//
}
}
结果,这次就变成浅拷贝了.这是几个意思呢?为啥String 和 Person都是引用类型.String就是深拷贝,Person就是浅拷贝嘞.还是看看黄金屋中怎么说的.
所以Object的clone()方法就是浅拷贝.只不过对于 int 和 String 以及一些不可变的类型是安全的.所以给了我们是深拷贝的假象.所以要想实现深拷贝,我们还要覆盖Object的clone()方法才行.
public class Test1 implements Cloneable {
public int age = 1;
public String name = "张三";
public Person person = new Person(1); @Override
protected Object clone() throws CloneNotSupportedException {
Test1 test1 = new Test1();
test1.age = age;
test1.name = name;
Person person = new Person(this.person.height);
test1.person = person;
return test1;
}
}
public class Run {
public static void main(String[] args)throws Exception{
Test1 test1 = new Test1();
Test1 test11 = (Test1) test1.clone();
test11.age = 2;
test11.name="李四";
test11.person.height = 3;
System.out.println(test1.age);//
System.out.println(test11.age);//
System.out.println(test1.name);//张三
System.out.println(test11.name);//李四
System.out.println(test1.person.height);//
System.out.println(test11.person.height);//
}
}
如此一来,则成功实现了深拷贝.PS实现深拷贝的方法有很多.例如更常见的利用序列化进行深拷贝.有兴趣的可以自行了解下.
关于lambda(只记得这一些十分皮毛的东西,假如要应用到真正的开发,确实不是短时间内,我可以做到的.)
先来看一个例子,说明下lambda的基本语法
public class Person {
private int age; public Person(int age) {
this.age = age;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Person[] p = new Person[3];
p[0] = new Person(3);
p[1] = new Person(2);
p[2] = new Person(1); Arrays.sort(p, (Person x, Person y) ->{return x.getAge() - y.getAge();}); for (Person person : p) {
System.out.println(person.getAge());
}
}
}
以上是使用Arrays中的sort()对Person对象数组进行排序,显而易见之前sort()中的第二个参数是一个比较器.此时我们没有new一个Comparator,实现compare()而是采用了lambda表达式.看看这个怪异的写法.两个参数,一个 -> 然后是一个表达式.嗯这么拆开看已经很明白啦.使用lambda表达式假装创建了一个Comparator接口的匿名内部类,我们只需要关注compare方法的实现细节即可.
还可以这样写.
public class Test {
public static void main(String[] args) {
Person[] p = new Person[3];
p[0] = new Person(3);
p[1] = new Person(2);
p[2] = new Person(1); Arrays.sort(p, ( x, y) ->x.getAge() - y.getAge()); for (Person person : p) {
System.out.println(person.getAge());
}
}
}
因为已经确定了数组中的类型为Person,所以省略.compare方法中只有一个行代码.不带大括号,也不使用return关键字.
关于lambda暂且放下.等待抽一个时间系统学习
java核心技术(第十版卷一)笔记(纯干货!)的更多相关文章
- java核心技术第十版 笔记
1.java区分大小写 2.类名是以大写字母开头 (驼峰) 3.http://docs.oracle.com/javase/specs java语言规范 4. /* */ 注释不能嵌套 5. Jav ...
- mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)
最后更新时间:2017-07-13 11:10:49 原始文章链接:http://www.lovebxm.com/2017/07/13/mongodb_primer/ MongoDB - 简介 官网: ...
- 【转】mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)
mongoDB 学习笔记纯干货(mongoose.增删改查.聚合.索引.连接.备份与恢复.监控等等) http://www.cnblogs.com/bxm0927/p/7159556.html
- java系列:《java核心技术 卷1》学习笔记,chapter 11 调试技巧
11. 6 调试技巧 1)一个不太为人所知却非常有效的技巧是在每个类中放一个main方法,这样就可以对每个类进行单元测试.这个方法可以保留,因为在java虚拟机只调用启动类的main方法. 2) ...
- 《java核心技术36讲》学习笔记-------杨晓峰(极客时间)
非常荣幸作为晓峰哥的同事,之前就看过这篇文章,重写读一遍,再学习学习. 一.开篇词 初级.中级:java和计算机科学基础.开源框架的使用:高级.专家:java io/nio.并发.虚拟机.底层源码.分 ...
- 《Java核心技术36讲》阅读笔记:Exception和Error有什么区别?
1.Exception 和 Error有什么区别?运行时异常与一般异常有什么区别? Exception和Error都继承自java.lang.Throwable.在Java中只有Throwable的实 ...
- 《Java核心技术36讲》阅读笔记:谈谈对Java平台的理解笔记
1. 谈谈你对Java平台的理解. Java是一种面向对象的语言,最显著的特性有两个方面: 一个就是一次编译,到处运行(Write once, run anywhere),能够非常容易的获得跨平台能力 ...
- 《Java核心技术卷1》读书笔记
一.基础 数据类型 Java是一种强类型语言,一共8种基本类型,没有无符号类型 整型:int(正负20亿).short(正负3万).long(巨多).byte(正负127) 浮点类型:float(正负 ...
- Express 学习笔记纯干货(Routing、Middleware、托管静态文件、view engine 等等)
原始文章链接:http://www.lovebxm.com/2017/07/14/express-primer/ 1. Express 简介 Express 是基于 Node.js 平台,快速.开放. ...
随机推荐
- Zabbix图表中文乱码(包含Docker安装乱码)
目录 Zabbix 4.0 版本 Zabbix 3.0 版本 Zabbix 4.0 Docker 版本 图表乱码问题解决 文章github 地址: 点我 最近在看 Zabbix 4.0 版本的官方文档 ...
- apache-tomcat-7.0.94在Windows上启动时,控制台黑窗口出现乱码解决
一.问题 二.解决 原因是tomcat日志编码的配置问题. 打开tomcat/conf/logging.properties配置文件. 把编码注释掉或者改为gbk就可以了. 参考:https://bl ...
- xshell使用zmodem拖拽上传
一.目的 windows向centos_linux服务器上传文件可以用ftp上传,但是没zmodem方便,zmodem拖拽上传,可以上传到指定的目录下. 二.安装使用 执行下面的命令安装后就可以使用了 ...
- 谈谈JavaScript Navigator 对象属性
Navigator 对象属性 可以在Navigator对象上使用以下属性: 属性 描述 appCodeName 返回浏览器的代码名称 appName 返回浏览器的名称 appVersion 返回浏览器 ...
- 汇编指令之ADC、SBB、XCHG、MOVS指令
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明.2019-08-25,23:52:49作者By-----溺心与沉浮----博客园 介绍完这些基础指令,后面就讲到汇编JCC指令了,我觉得介 ...
- WIP表解析
1,WIP的作用 负责纪录生产相关信息,生产什莫--工单的制定,下达,生产步鄹--工序及其移动,投入什莫--组件需求和投料,资源投入入和费用吸收,负责纪录生产成本的归集和差异分析,投入多少组件,资 ...
- odoo10学习笔记七:国际化、报表
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11189297.html 一:国际化(模块翻译) 我们开发的模块要国际化通用,就要开发出不同的语言支持. 这些 ...
- jenkins使用小技巧:jenkins构建出来的war/jar包如何带上SVN号?
在实际使用过程中,一般会这样比如说打出来的包是 mypackage.jar, 但是每次打出来都是固定的 mypackage.jar如何来区分和上一个包的区别呢? 一般来说,会把打出来的包带上个 svn ...
- DNS分离解析
实验环境: 一台内网(client)1块网卡:一台网关(dns)2块网卡:一台外网1块网卡 DNS服务器开启路由转发 [root@localhost ~]# vi /etc/sysctl.conf n ...
- vs解决方案文件出错
问题描述: 电脑死机,重启电脑后打开解决方案,提示“选择的文件不是有效的解决方案文件” 解决方案: 1. 先用记事本打开这个解决方案查看下,发现其中内容变成空白了? 2. 打开项目中的xxxx.vcx ...