Java学习笔记

************************Java基础加强**********************
this语句:
若要在一个构造方法中调用另一个构造方法,不能直接写,要用this语句,如 this(name) 调用
另外this语句必须写在最前面!!
this语句不能出现在一般方法中!一般方法也不能直接调用构造方法!
详见截图


静态属性存放在 方法区,也叫共享区、数据区(data segmen),另外类中的方法也存放在这里
成员变量(也叫实例变量)/ 静态成员变量(也叫类变量)
主函数可以有多个(可以理解为一个普通函数,只是虚拟机认识这东西),但一般就写一个!
默认的构造方法权限与类权限一致。


写工具类的时候,一般都是定义的静态方法,直接类名调用,根本不用创建工具类对象。
为了防止别人创建工具类对象占用空间,可以将工具类的构造方法私有化!


冒泡其实效率比较低,因为频繁在堆内存中交换两个数,比较耗时。优化方法之一是先不换,先临时
保存在栈内存中,最后再来换。


day06 05 javadoc帮助文档(API)的制作


*************
代码块执行顺序:静态代码块(给类初始化的,类一加载即执行)--> 构造代码块(给所有对象初始化的)
--> 构造方法(给特定对象初始化的)
另外注意 Person p = null; 是不会加载类的


直接写普通方法其实是省略了this.xxx(),静态方法中直接调用静态方法也是省略了类名.xxx()
注意静态东西和this无关,因为this是和当前对象有关的,而静态东西是先于对象加载的。


*******
单例设计模式:饿汉式/懒汉式 ,开发中一般用饿汉式,线程安全简单(面试重点)


方法重写:返回值类型必须是原类型子类,权限修饰符不能比父类更封闭,抛出的异常不能更宽泛
方法重载:只和参数有关,和返回值无关。如果仅仅是返回值不同会编译报错(搞不清究竟调哪一个)
注意:
如果父类中有一个private的方法,子类有一个public的同名方法,这不叫重写!!
因为父类那个私有的方法不对子类暴露,即子类不知道父类有那个方法,没法覆盖,编译能通过。


this本类对象,super父类对象,用法基本一样。
子类的所有的构造方法第一行默认都有一条隐式语句 super() !!!
但是如果第一行是this语句了,则没有隐式super(因为他们都得放第一行!不能共存!),此时,this
语句调用的那个构造函数的第一行也有隐式super(),所以不管怎么子类构造方法一定会调用父类构造方法。


注意:
只要子类不覆盖父类的成员变量,那么子类父类的这个成员共用一块内存空间!!即:
情况一:
父类有个 int a,子类直接继承的父类,这时如果new出一个子类把a改了,那么父类的a跟着变!!
情况二:
父类有个 int a,子类继承父类时也写个成员 int a,同样子类把a改了,父类的a不变!!


抽象类中也可以不定义抽象方法,这样做仅仅是不让该类建立对象。Java中其实有这样的类,但不多。
当一个方法目前不能明确做什么时,可以定义为abstract


注意:
接口中不能有构造方法,但是抽象类中可以有!
接口与接口之间也有继承关系,而且支持多继承!!!
但是,继承的两个接口中不能有仅返回值不同的方法。详见视频day07-13


一般类不能用private或static修饰,但是内部类可以(只有定义再成员位置上时)


匿名内部类是一种局部内部类(在一个方法里面定义的内部类),在java中语句必须写在方法里,匿名
内部类其实就是一条特殊的语句。
******特别注意*****
new B() 只是一个匿名对象,和内部类没关系
new B(){} 是个匿名内部类
上面两条语句都必须放在某个方法中


关于静态方法能否被继承?被重写?详见截图。我觉得很难说清,到底什么才算是继承可能也说不清。
子类能够用父类就是继承的话那么静态也能继承,但从多态角度来说并没有实现动态绑定。


***********
不能放在一起的修饰符:final和abstract,private和abstract,static和abstract,因为abstract修饰的方法是必须在其子类中
实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能
够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为调用的是父类的方法,
而父类的方法又是抽象的方法,又不能够调用,所以上的修饰符不能放在一起。


RuntimeException加深理解:就算函数中throw了,也可以不再函数上声明;声明了也可以不用处理。
因为当这类异常发生时,虚拟机不希望程序继续运行下去(如果try catch了就可以继续运行),而要对
代码进行修正。详见截图。


记住一点:catch是用于处理异常。没有catch就代表异常没有被处理过,如果该异常是检测时异常,则必须声明


直接if判断就行,为什么要用异常?
首先,它能防止输出不该输出的东西,最重要的是,它将正常流程代码和问题处理代码相分离,




***************多线程********************
调用start()方法开启线程并执行run()方法
直接调用run的话相当于普通的对象调用方法,并没有开启线程


static Thread currentThread() : 获取当前线程对象
getName() : 获取线程名称
可以通过setName() 或者构造函数 来设置线程名称(不设置的话默认是Thread-0,Thread-1...)


***死锁,经常发生在同步中嵌套同步,死锁小程序见 DeadLock.java 文件 面试可以要求写***
如果同步了还没解决线程安全问题,从两方面找原因:
1 操作同一资源的语句是不是都加了同步
2 锁是不是同一把锁
锁的话随便传一个对象就行,一般为了方便可以new一个Object传进来。但是如果要保证不同同步代码块
使用同一把锁,则要确保该对象是一致的!!比如程序中有一个Res类,则可以用Res.class做锁,因为
内存中Res.class对象是唯一的。


等待线程(wait住的)都存在线程池中,notify唤醒的都是线程池中的线程


**************************集合****************
注意集合中保存的都是对象的引用!不可能把整个对象存进去
Iterator其实是通过内部类的方式实现的
写迭代器推荐这种写法:
for (Iterator it = li.iterator() ; it.hasNext(); ){
System.out.println(it.next());
}
相比传统while写法,用完后it就释放了,比较节省内存


注意:List集合迭代(Iterator)时,不可以通过集合对象的方法操作集合中元素,会发生并发修改异常!
这时有一个List特有的迭代器解决问题: ListIterator,而且不仅能往后取,还能往前取
为什么只有list才有呢,因为List带角标


Vector是1.0版本就有的,后来基本被1.2版本的ArrayList代替了。两者功能基本一样。
Vector是同步的,比较慢;ArrayList不同步,比较快。
ArrayList初始数组长度为10,一旦超过了创建新数组长度加50%,即变成15;
Vector初始数组长度为10,一旦超过了长度加100%,即变成20,比较费空间。


在不能包含重复元素的集合中使用自定义类要特别注意:
需重写hashcode()方法和equals()方法!!


HashSet是无序的,它的儿子LinkedHashSet是有序的!
TreeSet虽然也是无序的,但是每次输出结果相同,自动按ASCII码排序!
TreeSet的要求是往里面存的对象必须具备比较性(实现了Comparable接口)!!否则它没办法帮你排序!
Java中很多对象都实现了Comparable接口,比如String,是按字典排序,
如果是自定义类,要记得实现comparable接口!
*************
TreeSet底层结构是二叉树!!
怎么让TreeSet变成有序的呢?即什么顺序放进去,什么顺序取出来
实现Comparable接口需要实现compareTo()方法,该方法返回正数表示大于,
返回0等于,返回负数小于。如果让该方法一直返回1,那么比较时永远是大于。
后放进去的元素一直往二叉树的右边排,因此TreeSet变成了有序!!


上面说的是按自然顺序排,即根据自定义类的CompareTo()方法,如果我需求发生了
变换,想根据另一种方式排序,修改CompareTo()方法不可取!此时可以用带参数的
TreeSet构造方法,传入一个实现了比较器(Comparator)的自定义类,该类中
实现类Comparator的compare()方法,在该方法中实现我们新的需求!


小总结:
凡是hash啥啥啥,要注意重写hashcode和equals方法
tree啥啥啥,要注意实现comparable接口,自定义要求排序,还要用到Comparator接口
即带tree的都涉及到两个比较器!!!一个自然顺序(Comparable),一个自定义(Comparator)!
**************


JDK升级无非就三个原因:
高效、简化书写、安全
泛型的出现是为了安全和简化,具体来说:避免了强转,把错误转移到了编译时期


***特别注意:Set底层就是用Map实现的。两列数据的当然能实现一列的


Map如果添加相同的key,则新的value值会覆盖原来的value值,并把原来的返回!


****遍历小总结:
List:三种方式,普通for、增强for、迭代器
Set:两种,增强for、迭代器
Map:两种,keySet、entrySet


注意Collection和Collections的区别!!!前面是接口,后面是工具类!!
Collections里面有很多好用的静态方法!!能实现排序,逆向排序,取最大值,加锁(非同步
变同步),交换等功能


数组转List:
如果数组是基本数据类型的,不能按照Arrays.asList()方法转,视频中应该是错的。
估计只能new一个集合一个一个add()。如果是String数组的话,直接转就行。
集合转数组:
String[] arr = list.toArray(new String[list.size()]);


************************** IO ××××××××××××××××××××
注意 new FileWriter("aaa.txt")时,若没有则创建,若有则覆盖了创建新的。
     new FileWriter("aaa.txt",true) 存在的话在末尾追加


Unix系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“ <回车><换行>”,
即“\r\n”;Mac系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac系统下的文件在Windows
里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能
会多出一个^M符号


缓冲区的出现是为了提高流的操作效率而出现的。
所有在创建缓冲区之前,必须要先有流对象
缓冲区中的 newLine()换行方法是跨平台的。
BufferedReader 的readLine() 方法读一行(不包含换行符),读到了末尾返回null
LineNumberReader 是BufferedReader的子类,可以通过get、set方法获取行号!


************************
GBK编码,一个汉字占两个字节。 (简体中文版操作系统编码默认都是GBK,可以通过查看系统信息来获取)
UTF-16编码,通常汉字占两个字节,
UTF-8编码是变长编码,通常汉字占三个字节,扩展B区以后的汉字占四个字节
Java中一个字符占两个字节(一个汉字也可以是一个字符),C++中一个字符一个字节
特别注意字符串中:
一个英文字符占1个字节,而中文字符根据编码的不同所占字节数也不同。在UTF-8编码下,
一个中文字符占3个字节;而使用GBK编码时一个中文字符占2个字节。


注意:
直接字节流的话不需要刷新也能写入文件,而字符流需要(不可能存入半个汉字...)
带Buffer的话另说。


************必须记住,涉及到键盘录入,就用这句!!!!!
BufferedReader br = new BufferedReader(new InputStreamReader(System.in))


****** ImportantIODemo 很有用的一个例子!!!看Eclipse!!!


***************File类
写路径这样可以跨平台:
File f = new File("C:"+File.separator+"abc"+File.separator+"a.txt");
貌似直接写Linux中的 “/” 也没问题,Windows也能认识,但万一有一天不支持了呢。。。


注意:
File类的创建文件方法和输出流的不一样
File方法 createNewFile() 如果不存在则创建,返回true;存在则不创建,返回false
输出流一定创建文件,如果存在则会覆盖
另外不要弄错:new出一个File只是创建了一个和文件或文件夹相关联的类,不是创建文件!
该文件还不一定存在!!
getPath() 获取相对路径,但如果你new file的时候写的是绝对,那获取的还是绝对
getAbsolutePath() 不管怎样获取的都是绝对路径
注意这些方法不管文件存不存在都能用!


PrintStream、PrintWriter 没有对应的输入流
SequenceInputStream 没有对应的输出流,这个流可以把多个输入流拼接起来输入!


有点疑惑BufferedInputStream比InputStream强在哪?不像BufferedReader能一次读一行。
可能就是效率更高了吧,一般用InputStream的话是先写到一个1024的字节数组,可以参见
IO切割的截图。


实现对象的序列化,需要实现一个Serializable接口,大概是现在为止最爽的接口,因为里面没方法!
这样的接口又叫标记接口!实现了这个接口就说明具备了序列化的资格,
只能把堆里面东西序列化,静态的成员无法被序列化。transient关键字可以让非静态成员不被序列化


编码问题:神奇的“联通”!!!


******************************网络通信
127.0.0.1 本地回环地址,装网卡就有的,可以用来测试网卡有没有坏!
DatagramPacket对象的方法receive()是个阻塞式方法,该方法一直等着接收数据!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值