#方法重载
--定义:如果一个类中包含了两个或两个以上方法的方法名相同,但形参列表不同,则被称为方法重载
Java程序中确定一个程序的三要素:
--调用者,也者就是方法的所属者,既可以是类,也可以对象
--方法名,方法的标识
--形参列表,当调用方法时,系统将会根据传入的实参列表匹配
方法重载的要求就是两同一不同:同一个类中方法名相同,参数列表不同,至于方法的其他部分,如方返回值类型、修饰符等,与方法重载没有任何关系
#方法重写
--方法的重写要遵“两同两小一大”规则,“两同”即方法名相同、形参列表相同;“两小”指的是子类方法返回值类型应该比父类方法的返回值的类型更小或者相等,子类方法声明抛出的异常类应该比父类方法声明抛出的异常类更小或者相等;“一大”指的是子类方法的访问权限应该比父类方法的访问权限更大或者相等。
--注意:覆盖方法的被覆盖方法要么都是类方法,要么都是实例,不能一个是类方法,一个是实例方法,例如,如下的代码将会发生编译错误
class BaseClass
{
public static void test(){...}
}
class SubClass rxtends BaseClass
{
public void test(){...}
}
#调用父类构造器
--子类构造器调用父类构造器分如下几种情况:
--子类构造器执行体的第一行使用super显示调用父类构造器,系统将根据super调用里传入的实参列表调用父类对应的构造器
--子类构造器执行体的第一行代码使用this显示调用本类中重载的构造器,系统将会根据this调用里传入的实参列表调用本类中的另一构造器,执行本类中另一构造器时即会调用父类构造器
--子类构造器执行体中既没有super调用,又没有this调用时,系统将会在执行子类构造器之前,隐式调用父类无参数构造器
#程序清单
public class Base
{
public Base{
test();
}
public void test(){
System.out.println("将被子类重写的方法")
}
}
public class Sub extends Base{
private String name;
public void test{
System.out.println(name.length());
}
}
public void main(String[] args){
//下面的代码将会发生空指针异常
Sub s = new Sub();
}
--当系统试图创建Sub对象是,同样会先执行其父类构造器,如果父类构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法。当创建Sub对象时,回先执行Base类中的构造器,而Base构造器中调用了被子类重写后的test()方法,而此时Sub对象的name实例变量是null,因此发生空指针异常
# ==和equals方法
equals()方法是Object类提供一个实例方法,因此所有的引用变量都可以调用该方法来判断是否与其他引用变量相等。但使用这个方法判断两个对象相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true。因此这个Object类提供的equals() 方法没有太大的实际意义,如果希望采用自定义的相等标准,则可采用重写equals方法来实现
提示:
String 已经重写了Object的equals()方法,String的equals方法判断两个字符串相等的标准是:只要两个字符串所包含的字符序列相同,通过equals()比较将返回true, 否则将返回false
instanceof:当前面的对象是后面的类的实例或者其子类的实例时都将返回true
##类成员
--定义:由static关键字修饰的成员就是类成员,类成员包括:类变量、类方法、静态初始化快
--在Java类中只能包含成员变量、方法、构造器、初始化块、内部类(包括接口、枚举)5种成员,其中static可以修饰变量、方法、初始化快、内部类(包括接口、枚举),以static修饰的成员就是类成员,类成员属于整个类,而不属于单个对象
--类变量属于整个类,当系统第一次准备使用该类时,系统会为该变量分配内存空间,类变量开始生成,直到类被卸载, 该类所占的内存空间才会被垃圾回收机制回收,类成员的生命周期等同于该类的生命周期,当类初始化完成后,类成员也被初始化完成
--类变量的访问方法:可以通过类名直接访问,也可以创建类的对象来访问,但通过类的对象来访问类变量时,并不是访问该对象所拥有的变量,因为当系统创建该类对象时,系统不会再为类变量分配内存,也不会再次对类变量进行初始化,对象根本不拥有对应类的类变量,可以这样理解:通过对象来访问类变量时,系统会在底层转换为通过该类访问类变量
#final
##private
--仅在当前类中使用,其子类无法访问,所以子类无法重写该方法,如果子类定义一个与父类private方法有相同方法名、相同形参列表、相同返回值类型的方法,也不是方法重写,只是重新定义一个方法
--所以,即使使用了final修饰private方法,依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值得方法
##final类
--final修饰的类不可以有子类
#不可变类
--不可变类的意思是创建该类的实例后,该实例的实例变量是不可改变的。
--如果需要创建自定义的不可变量,应遵守如下规则
--使用private或者final修饰符修饰该类的成员变量
--提供带参数构造器,用于传入参数来初始化类里的成员变量
--仅为该类的成员变量提供getter方法,不要提供setter方法,因为普通变量方法无法修改被final修饰的成员变量
--如果需要,重写Object类提供的equals()和hasCode()方法,equals()方法根据关键成员变量来判断两个对象是否相等,除此之外,还应该保证两个用equals方法判断相等的对象的hasCode()也相等
--例如,Java.lang.String根据对象的字符序列来作为相等的标准
public class ImmutableStringTest {
public static void main(String[] args){
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);//返回false
System.out.println(str1.equals(str2));//返回true
//下面的两个哈希值相等
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
}
}
#成员变量和局部变量
--成员变量指的是在类里定义的变量:实例变量(不以static修饰)、类变量(static修饰)
--局部变量指的是在方法里定义的变量:形参、方法局部变量、代码块局部变量
--局部变量初始化后,必须显示初始化,局部变量不属于任何类或者实例,因此总是保存在其所在方法的栈内存中
--如果局变量是基本类型的变量,则直接把这个变量的值保存在该变量对应的内存中
--如果局部变量是一个引用类型的变量,则这个变量里存放的是地址,通过该地址引用到该变量实际引用的对象或者数组
#super
如果子类里没有包含和父类同名的成员变量,那么在子类实例方法中访问该成员变量时,则无须使用super或父类名作为调用者。如果在某个方法中访问名为a的成员变量,但没有显示指定调用者,则系统查找a的顺序为:
(1)查找该方法中是否有名为a的局部变量
(2)查找当前类中是否包含为a成员变量
(3)查找a的直接父类是否包含名为a的成员变量,依次上溯a的所有父类,直到java.lang.Object类,如果最终找不到名为a的成员变量,则系统出现编译错误
#多态
--Java引用变量有两个类型,一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,如果编译时类型和运行时类型不一样,就可能出现多态
#引用类型的强制转换
--引用类型的转换只能在具有继承关系的两个类型中之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误,如果试图将一个父类实例转化成子类类型,则这个对象必须实际上是子类的实例才行(即编译时类型为父类类型,而运行时类型是子类类型)否则将在运行时发生ClassCastException异常
#instanceof 运算符
instanceof 运算符的前一个操作数通常是一个引用类型的变量,后一个操作数通常是类(也可以是接口,可以把接口理解为特殊的类),它用于判断前面的对象是否是后面的类或者其子类、实现类的实例。如果是,则返回true,否则返回false
#为了保证父类具有良好的封装性,不会被子类随意改变,设计父类时应该遵守如下规则
--尽量隐藏父类的内部数据,尽量把父类的所有成员都设置成private访问类型,不要让子类直接访问父类的成员变量
--不要让子类可随意访问、修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private修饰,让子类无法访问该方法,如果父类中的方法需要被外部其他类调用,则必须以public修饰,但又不希望子类重写该方法,可以使用final来修饰符该方法,如果希望父类的某个方法被子类重写,但不希望其他类自由访问,可以使用protected来修饰。
--尽量不要在父类构造器中调用将要被子类重写的方法
#初始化代码块
--前面定义的代码块先执行,后面定义的代码块后执行
--初始化代码块的修饰符只能是static
--代码块里面的代码可以包含任何可执行性语句,包括定义局部变量,调用其他对象的方法,以及使用分支、循环语句等
--无法通过类、对象调用,只在创建Java对象时隐式执行,而且在执行构造器之前执行
##静态初始化代码块
--类初始化阶段执行静态初始化代码块
--先执行java.lang.Object类(如果有),然后执行其父类的静态初始化代码块.....最后才执行该类的静态初始化块
--一旦类初始化成功后,类在该内存中就存在了,所以第二次创建对象时,无须再次对类进行类初始化
#包装类
--Java为8个基本类型提供了对应的包装类,通过这些包装类可以把8个基本类型的值包装成对象使用
基本数据类型和包装类的对应关系
--自动装箱:把一个基本类型变量直接赋值给对应的包装类变量,或者赋给Object变量(Object是所有类的父类,子类对象可以直接赋给父类变量)
--自动拆箱:直接把包装类对象直接赋给对应的基本类型变量
public class AutoBoxingUnboxing{
public static void main(String[] args){
//直接把一个基本类型变量赋给Integer对象
Integer inObj = 5;
//直接把一个boolean类型变量赋给一个Object对象类型的变量
Object boolObj = true;
//直接把一个Integer对象赋给int类型的变量
int it = innObj;
if(boolObj instanceof Boolean){
//先把Object对象强制类型转换为Boolean类型,再赋给boolean变量
boolean b = (Boolean)boolObj;
System..out.println(b);
}
}
}