新进公司的初级程序员,看了公司的项目,目前没啥事做就在看Think In Java,然后想把自己的收获记录起来。这是本人第一次写博客。
2018年5月25日
1.创建一个新对象之后,直接输出该对象,会默认调用Object(所有类都默认继承Object类)的toString方法,也就是输出了该对象的地址(“@”符号加上一堆没有意义的数字和字母),如果该对象重写了toString方法,则会打印出重写方法中定义的内容。
例子:
(1)没有重写toString()时:
public class User {
}
public class test { public static void main(String[] args) { User user = new User(); System.out.println(user); } }
输出结果为:com.eno.springbootweb.domain.User@7291c18f
(2)重写了toString()方法
public class User { @Override public String toString() { return "123"; } }
public class test { public static void main(String[] args) { User user = new User(); System.out.println(user); } }输出结果:123
2.多态的缺陷,“覆盖”私有方法
例子:
class A{ private void f(){ System.out.println("a"); } public static void main(String[] args) { A a = new Test(); a.f(); } } public class Test extends A{ public void f(){ System.out.println("test"); } }
输出结果为:a
我们期待的是输出test,但是由于private修饰符修饰的方法是被自动认为是final的方法,而且对子类是隐蔽的。因此,这种情况下,子类中的f()方法就是一个全新的方法;既然父类中的方法f()方法在子类中不可见,因此甚至也不能被重载。
结论:只有非private方法才可以被覆盖;但是还需要密切注意覆盖private方法的现象,这是虽然编译器不会报错,但是也不会按照我们所期望的来执行。所以在子类中,对于父类中的private的方法最好采用不同的名字。
3.使用继承和组合的场景
在使用继承的时候只要考虑是否需要向上转型,如果需要则使用继承,不需要使用组合效率更高。
4.代理类
代码如下:
class A{ public String a(){ return "a"; } public String b(){ return "b"; } } class Agent{ private A a = new A(); public void getA(){ System.out.println(a.a()); } public void getB(){ System.out.println(a.b()); } } public class Test{ public static void main(String[] args) { Agent agent = new Agent(); agent.getA(); agent.getB(); } }
5.组合、继承以及多态在构建顺序上的作用(构造器、成员变量加载的顺序)
例子:
class A{ A(){ System.out.println("A"); } } class B{ B(){ System.out.println("B"); } } class C{ C(){ System.out.println("C"); } } class C1 extends C{ C1(){ System.out.println("C1"); } } public class Test extends C1{ private A a = new A(); private B b = new B(); public Test(){ System.out.println("test"); } public static void main(String[] args) { new Test(); } }
结果:
C
C1
A
B
test
结论:
构建顺序首先是找到该对象的最上层的基类,然后是下一级子类直到加载到当前类,加载到本类的对象时,会先按成员声明的顺序加载成员变量,最后在调用该类的构造器(同一类中构造器会在成员变量初始化之后被调用)。
6.构造器内部的多态方法的行为
class A{ void a(){ System.out.println("A.a()"); } A(){ System.out.println("A() before a()"); a(); System.out.println("A() after a()"); } } class B extends A{ private int radius = 1; B(int r){ radius = r; System.out.println("B.B().redius = " + radius); } void a() { System.out.println("B.a().radius = " + radius); } } public class Test{ public static void main(String[] args) { new B(5); } }
结果:
A() before a()
B.a().radius = 0
A() after a()
B.B().redius = 5
结论:
从结果可以看出,在基类的构造器中调用了被子类重写的方法,会执行子类中重写的方法,而不是执行基类中的方法。而在调用到子类中重写的方法的时候,子类(B)还没有被构造,也就导致了radius并没有被初始化(输出结果为0)。因此,编写构造器时有一条有效的准则:“用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法”。
7、Collenction集合
ArrayList和LinkedList都是List类型,他们都按照插入的顺序保存元素。两者的区别主要是在执行某些类型的操作时的性能,ArrayList遍历只花费常量时间,LinkedList在插入删除元素是花费常量时间。
HashSet、TreeSet和LinkedHashSet都是Set类型,Set中的元素不可重复,HashSet(使用了散列)是快速获取元素的方法,因此不考虑存储顺序,TreeSet(使用红-黑树)会按照比较结果升序保存对象, LinkedHashSet会按添加的顺序保存对象。
Map不用考虑尺寸问题,因为它自己会自动地调整尺寸。HashMap和HashSet一样提供了最快的查找技术,也没有按照任何明显的顺序进行保存元素,TreeMap会按照比较结果升序保存对象,LinkedHashMap会按添加的顺序保存键,同时保留了HashMap的查询速度。
8、List list = list1.subList(index1, index2)方法从一个List中截取一部分内容,然后将这个结果赋给另一个list之后,使用list1.containsAll(list)会显示true,就算我们使用了Collection.sort()和Collection.shuffle()之后,再调用list1.containsAll(list)仍返回true,由此看出顺序并不重要,因为subList()所产生的列表的幕后是初始列表,因此,对所返回的列表的修改都会反映到初始列表中。测试代码如下:
public class Test{ public static void main(String[] args) { List list1 = new ArrayList(); list1.add(1); list1.add(3); list1.add(2); list1.add(9); list1.add(4); System.out.println("list1" + list1.toString()); List list2 = list1.subList(0,3); Collections.sort(list2); System.out.println("sort list2" + list2.toString()); System.out.println("list1" + list1.toString()); System.out.println(list1.containsAll(list2)); Collections.shuffle(list2); System.out.println("shuffle list2" + list2.toString()); System.out.println(list1.toString()); System.out.println("list1" + list1.containsAll(list2)); } }
结果为:
还有几个个常用方法,retainAll()取交集,removeAll()移除所有元素,需要注意的是这两个方法都是基于equals()方法的。
set(index, obj),替换指定位置的元素。addAll()可以追加元素到列表中,也可以从指定位置追加,isEmpty()用来判断是否为空,clear()清除列表中的内容,toArray()将集合转换为数组类型等。
9、我们都知道queue队列是先进先出的模式(通过等待时长来判断是否为先进的元素),但有些时候需要在队列中基于优先级处理对象,于是就出现了PriorityQueue。
PriorityQueue类在Java1.5中引入并作为 Java Collections Framework 的一部分。PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。
优先队列不允许空值,而且不支持non-comparable(不可比较)的对象,比如用户自定义的类。优先队列要求使用Java Comparable和Comparator接口给对象排序,并且在排序时会按照优先级处理其中的元素。
优先队列的头是基于自然排序或者Comparator排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。
优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。
PriorityQueue是非线程安全的,所以Java提供了PriorityBlockingQueue(实现BlockingQueue接口)用于Java多线程环境。
还没看多少,持续更新中。。。。。。)