2017年4月10日19:41:44 仅仅用于打好基础
1. 在Java中,所有的继承都是公有继承,而没有C++中的私有继承和保护继承!
2.关键字super的使用方法:
(1) 子类中想调用父类中的方法,可以使用关键字super,格式super.function();
(2) Java中的super与C++中的this引用是类似的概念,但是super并不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字!
(3)为什么子类构造器中需要使用super关键字
a) 由于子类的构造器不能方位父类的私有域,所以必须利用父类的构造器对这部分私有域进行初始化,可以使用super实现对超类构造器的调用。
b) 使用super调用构造器的语句必须是子类构造器的第一条语句!
(4) 关键字this有两个用途:1.引用隐式参数.2调用该类其他的构造器
关键字super也有两个用途:1.调用超类的方法. 2.调用超类的构造器
this和super调用构造器的语句都只能作为另一个构造器的第一条语句出现。
3. 如果子类的构造器没有显示的调用父类的构造器,那么就将自动的调用超类默任(没有参数)的构造器;如果父类没有不带参数的构造器没并且在子类的构造器中又没有显示得调用超类的其他构造器,则Java编译器将报告错误。
4.is-a(置换法则/里氏替换原则):程序中出现超类对象的任何地方都可以中子类对象替换,也就是通常所说的向上转换时可行的,但是向下转换是不可行的。
向上类型转换:表示的子类向父类的强制类型转换;(允许)
向下类型转换:表示的是父类向子类的强制类型转换。(不允许)ClassCastException异常
在类转换之前,可以用instanceof()函数进行检查是否转换成功
5. 重载(overload):方法名相同,参数不同;(同一个类中,例如构造器)
覆盖/重写(override):方法相同,参数名相同,实现不同;(子类和父类)
需要保证返回类型的兼容性(允许子类将覆盖方法的返回类型定义为原返回类型的子类型)
在覆盖一个方法的时候,子类方法不能低于超类方法的可见性!特别是,如果超类方法是public,子类方法一定声明为public.
6.概念:多态、动态绑定、重载解析、静态绑定
(1) 前三个概念多态、动态绑定、重载解析是联系在一起的。
1) 多态:一个对象变量可以指示所踪实际类型的现象
2) 动态绑定:在运行时能够自动地选择调用哪个方法的现象
动态绑定有一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展。
3) 重载解析:如果在所有名为f的方法中存在一个与提供的参数类型完全匹配,就选择这个方法。
(2) 静态绑定:如果是private方法、Static方法、final方法或者构造器,那么编译器将可以准确地知道应该调用那个方法.
7. 如果方法很简短、被频繁调用且没有真正地被覆盖,那么即时编译器就会将这个方法进行内联处理。
8.抽象类:
1) 抽象类包含一个或多个抽象方法(不是至少包含一个抽象方法,不包含抽象方法,也可以将类声明为抽象类),也可以包含具体数据和具体方法;
2) 抽象方法没有方法体,也就是没有{};
3) 抽象类不能被实例化(创建这个类的对象) new Person("Vince Vu");但是可以创建一个具体子类的对象
4) 可以定义一个抽象类的对象变量,但是他只能引用非抽象子类的对象。
Person p = new Student("Vince Vu",Economics);
而C++中是将一个方法加“=0”,即纯虚函数;只要有一个纯虚函数,这个类就是抽象类。
9. 受保护访问(protected)
(1) Java中的受保护部分对所有子类及同一个包中的所有其他类都可见
(2) 谨慎使用protected属性,因为会违背数据封装原则。
10.Java用于控制可见性:
1) 仅对本类可见-private
2) 对所有类可见-public
3) 对本包和所有子类可见----protected
4) 对本包可见---默认,不需要修饰符
11.Object:所有类的超类
在Java中,只有基本类型不是对象;所有数组类型,不管是对象数组还是基本类型的数组都扩展与Object类.
12.equals方法
(1) Object类中的equals方法用于检测一个对象是否等于另外一个对象,判断的是两个对象是否具有相同的引用。
(2) 对于多数类来说,这种判断并没有意义。然而,经常需要检测两个对象状态的相等性,如果两个对象的状态相等,就认为这两个对象是相等的。
(3) 为了防备两个比较的对象的属性为空,需要使用Objects.equals方法,如果两个参数都为null,则返回true;有一个为空,则返回false;
如果两个参数都不为null,则调用a.equals(b)
(4) 在子类中定义equals方法时,首先调用超类的equals。如果检测失败,对象就不想等;如果超类中的域都相等,就要比较子类中的实例域。
(5) equals与==的区别:具体可以参照http://www.cnblogs.com/bluestorm/archive/2012/03/02/2377615.html
1) 在字符串的比较中,equals方法比较的是两个字符串对象的类容是否相同,而==比较的两个字符串对象是否引用的同一个对象,也就是说两个字符串对象在堆中的首地址是否相同。
2) 但是equals对于stringbuilder对象的比较不适用,因为sringbuilder没有重新定义equals这个方法,而是直接调用的Object类的equals方法,因此
StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("a");
结果: s1.equals(s2) //是false
3) 对于非字符串变量来说,"=="和"equals"方法的作用是相同的,都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。
13. 编写一个完美的equals方法的建议:
(1) 显示参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量
(2) 检测this与otherObject是否引用同一个对象:
if( this == otherObject) return true;
这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价要小得多。
(3) 检测otherObject是否为null,如果为null,返回false;
if( otherObject == null ) return false;
(4) 比较this与otherObject是否属于同一个类。如果equals的语义(实现)在每个子类中都有所改变,就使用getClass来检测:
if( getClass != otherObject.getClass()) return false;
如果所有的子类都拥有统一的语义,就使用instanceof检测:
if( !( otherObject instanceof ClassName)) return false;
(5) 将otherObject转换为相应的类类型变量
ClassName other = (ClassName) otherObject
(6) 现在开始对所有需要比较的域进行比较了
使用==比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true;否则返回false
return field1 == other.field1 && Objects.equals( field2,other.field2);
如果在子类中重新定义equals,就要在其中包含调用super.equals(other).
对于数组类型的域,可以使用静态的Arrays.equals方法检测相应的数组元素是否相等。
具体如何重写,可以参见这篇博客:http://www.cnblogs.com/TinyWalker/p/4834685.html
14. 散列码hashCode方法:
(1) 散列码(hash code )是由对象导出的一个整数值,每一个对象都有一个默认的散列码,其值为对象的存储地址
(2) 最好使用null安全的方法Objects.hashCode.如果其参数为null,这个方法会返回0,否则返回对参数调用hashCode的结果。
name.hashCode() =>Object.hashCode(name);
(3) 需要组合多个散列值时,可以调用Objects.hash并提供多个参数。这个方法会对各个参数调用Objects.hashCode,并组合这些散列值。
(4) 如果重新放一equals方法,就必须重新定义hashCode方法;
15.toString()方法:
(1) 用于返回表示对象值的字符串,Point类的toString方法将返回下面这样的字符串: java.awt.Point[x=10,y=20];
(2) 绝大多数的toString方法都遵循这样的格式:类的名字,随后是一对方括号括起来的域(变量)值
eg: public String toString(){
return "Employ[name="+name+",salary="+salary+",hireDay="+hireDay+"]";
}
进一步优化,通过调用getClass().getName()获得类名的字符串,而不要将类名硬加到toString方法中:
eg: public String toString(){
return getClass().getName()+"[name="+name+",salary="+salary+",hireDay="+hireDay+"]";
}
设计子类的程序员也应该定义自己的toString方法,并将子类域的描述添加进去。如果超类使用了getClass().getName(),那么子类只要调用super.toString()就可以了。
public String toString(){
return super.toString()+"[bonus="+bonus+"]";
}
(3) 随处可见toString方法的主要原因是:只要对象与一个字符串通过操作符+连接起来,Java编译就会自动的调用toString方法,以便获得这个对象的字符串描述。
(4) Object类定义了toString方法,用来打印输出对象所属的类名和散列码。
System.out.println(System.out); => java.io.PrintStream@2f6684
16.数组列表ArrayList:
(1) add()方法:将元素添加到数组列表中
(2) size()方法:返回数组列表中包含的实际元素数目。
(3) trimToSize():用于很确定数组列表大小后,将多余的空间回收(垃圾回收机制),也就是实际有所多少个元素就分配多大的空间;
(4) get()和set()方法用于访问和设置数组列表中的元素
17. Java的ArrayList与C++的Vector的区别:
(1) C++的Vector为了访问元素方便,重载了[]运算符;
(2) C++的向量Vector是值拷贝。如果a和b是两个向量,赋值操作a=b将会构造一个与b长度相同的新向量a,并将所有元素由b拷贝到a;
而在Java中,这条赋值语句的操作结果是让a和b引用同一个数组列表。 18.对象包装器类与自动装箱
(1) 对象包装器类:Integer、Short、Long、Float、Double、Byte、Charater、Void和Boolean( 前6个类派生于公共的超类Number)
(2) 对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。
(3) 对象包装器类还是final,也就是不能被继承,因此不能定义它们的子类。
(4) 泛型的尖括号<>中不能是基本类型
(5) 自动装箱: 将基本类型赋值给包装器类型,list.add(3) 自动变换成list.add(Integer.valueOf(3));
Integer i = 100; => Integer i = Integer.valueOf(100);
自动拆箱:将包装器类赋值给基本类型时,就会自动地拆箱
int n = list.get(i); => int n = list.get(i).intValue();
(6) 自动装箱的要求:boolean、byte、char≤127;
介于-128~127之间的short和int被包装到固定的对象中;
更详细可以参考:http://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html
(7) 使用数值对象包装器还有另外一个好处:可以将某些基本方法放置在包装器中,例如将一个数字字符串转换成数值。
int x = Integer.parseInt(s);
这里与Integer对象没有任何关系,ParseInt是一个静态方法。但Integer类是放置这个方法的一个好地方。
19.枚举类
public enum Size{ SMALL,MEDIUM,LARGE,EXTRA_LARGE}
这个声明定义的类型是一个类,他刚好有4个实例,因此,在比较两个枚举类型的值时,永远不需要调用equals,而直接使用==就可以了
(1) 所有的枚举类都是Enum类的子类
(2) 枚举类的方法:
1) toString:返回枚举常量名 Size.SMALL.toString() 返回字符串“SMALL”
2) toString的逆方法是静态方法valueOf: Size s = Enum.valueOf(Size.class,"SMALL"); 将s设置成Size.SMALL;
3) 每个枚举类型都有一个静态的values方法,它将返回一个包含全部枚举值的数组。
Size [] values = Size.values();
返回包含元素Size.SMALL,SIZE.MEDIUM.....的数组
4) ordinal方法返回enum声明中枚举常量的位置,位置从0开始计数
eg: Size.MEDIUM.ordinal() 返回1