1. 封装
将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
1.1 私有化的流程
a.私有化成员变量使用private关键字修饰。
b.提供公有的get成员变量和set成员变量方法,并在set方法体中进行合理性的判断。
1.2 访问控制符
如果一个java源文件里定义的所有类都没有使用public修饰,则这个java源文件的文件名可以是一切合法的文件名,但如果一个java源文件里定义了一个public修饰的类,则这个源文件的文件名必须与public修饰的类的类名相同。
如果一个类主要用作其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
1.3 package、import、import static
package
Oracle允许在类名前增加一个前缀来限定这个类。java引入了包(package)机制,提供了类的多层命名空间。用于解决类的命名冲突、类文件管理等问题。java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的【类库单元】。如果希望把一个类放在指定的包结构下,应该在java源程序的第一个非注释行放置如下代码:
package packageName;
Oracle公司为了避免各个公司之间类名的重复,建议使用公司Internet域名倒写来作为包名。例如:
域名是crazyit.org 则所有类都建议放在org.crazyit 包及其子包下。
import
java默认所有源文件导入java.lang包下的所有类。使用import语句导入指定包下全部类的用法:*
import static
JDK1.5以后新增了一种静态导入的语法:用于导入指定类的某个静态成员变量、方法或全部的静态成员变量、方法。
导入单个静态成员变量、方法的格式
import static package.subpackage..ClassName.fieldName/mothodName;
导入全部静态成员变量、方法的格式
import static package.subpackage..ClassName.*;
2. 类的继承
继承是实现软件复用,并对之增加、修改与扩展的重要手段。java的继承具有单继承的特点,每个子类只有一个直接父类。
2.1 继承的特点
使用extends关键字来表达继承关系。超类/父类/基类 派生类/子类,父类子类的关系是一种一般和特殊的关系。
继承本质上就是自定义类去吸收现有类中已有的成员,而在自定义类中编写独有成员的机制。
注意事项:
(1)子类可以继承父类中的成员变量,包括私有成员变量,但不能直接访问
子类不可以继承父类中的构造方法和私有成员方法
(2)当创建子类的对象时,会自动调用父类中的无参构造方法,相当于增加super()的效果0
(3)在java语言中只支持单继承,也就是一个子类只能有一个父类,但一个父类可以有多个子类
(4)不能滥用继承,必须满足子类 is a 父类的逻辑关系
2.2 命名的由来
java使用extends作为继承的关键字,extends关键字在英文中是扩展,而不是继承。
子类是对父类的扩展,子类是一种特殊的父类。所以扩展比继承描述的更加准确。
为什么国内把extends翻译为继承?
除了与历史原因有关外,子类扩展了父类,将可以获得父类的全部成员变量和方法,这与汉语中的继承(子辈从父辈那里获得一笔财富称为继承)具有很好的类似性。
2.3 造器继承super
java的子类不能继承父类的构造器,只可调用。
子类的构造方法中必须通过super关键字调用父类的构造方法。
当子类的构造方法中没有调用父类的构造方法,也没有使用this()调用本类构造,java编译器会自动地加入对父类无参构造方法的调用(如果该父类没有无参的构造方法,会编译错误)。
3. 多态
java引用变量有两种类型:
- 编译时类型:由声明该变量时使用的类型决定。
- 运行时类型:由实际赋给该变量的对象决定。
如果编译时类型和运行时类型不一致,就可能出现所谓的多态。
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。
3.1 多态的定义
相同类型的变量,调用同一个方法时呈现出多种不同的行为特征,这就是多态。
多态的本质:父类的引用变量指向一个子类的对象,形成多态。因为子类其实是一种特殊的父类,所以java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者成为向上转型,向上转型由系统自动完成。
多态的作用:在于屏蔽不同子类的差异性,实现通用的编程,根据实参传递的不同产生不同的效果即通过属于不同类型的实参传递,调用不同类中的方法。
父类类型 引用名 = new 子类类型();
Person p = new Student();
p.show();
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。
在编译阶段p是Person类型的(父类)
在运行阶段p指向的是Student类型的对象,因此最终调用的是Student类中的show()方法.
因此,编写java代码时,引用变量只能【调用】声明该变量时所用类里包含的方法。
只能调用Person类中的show()方法,不能直接使用子类中扩展的属性/方法,除非进行强转。
【如果子类重写了方法,静态方法调用父类的,非静态方法调用子类的】
3.2 常见的多态
- 基本类型的多态 byte b = 3; short s = 3; int i = 3; long l = 3;
本质其实就是基本类型的自动类型转换 - 方法多态 重载(同名 但不是一个方法)和重写(父类/子类形态不一样)
- 对象多态 就是父子类对象之间的多态
- 参数多态 本质就是基本类型和对象多态,即用父类类型可以代表父类和所有子类的对象
3.3 父类引用指向子类对象
1)父类的引用可以直接调用父类的方法。
2)父类的引用不可以【直接调用】子类的方法。(强转后可以)
3)编译阶段调用父类的,运行阶段最终调用子类的版本
4)对于【静态方法】来说,最终调用父类的版本
原因:??????
3.4 引用类型之间的转化
引用类型之间的转换只能在具有继承关系的两个类型之间,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出错。
1)子类类型向父类类型之间的转换自动完成,因此是自动类型转换。
2)父类类型向子类类型之间的转换需要进行【强制类型转换】:
目标类型 目标类型的引用 = (目标类型)源类型的引用
强制类型转换: Student s = (Student)p;
不是把p的类型转换了,而是定义了一个新变量s,s的类型是Student,p还是Person;
3)如果试图把一个父类实例转换成子类类型,则这个对象必须实际上是子类实例才行(即编译时类型为父类类型,而运行时类型时子类类型),否则将在运行时引发ClassCastException异常。只要拥有父子类关系则进行强制类型转换时,编译阶段不会报错,当转换的目标类型不是该引用真正指向的类型时,则运行阶段产生类型转换异常ClassCastException
4)为了避免上述错误的发生,可以使用instanceof运算符进行判断
3.5 instanceof运算符
为了避免上述错误的发生,可以使用instanceof运算符进行判断对象的类型
if (引用变量名 instanceof 引用类型) { 语句块; }
如:if (p instanceof Person) {语句块;}
当引用变量名真正指向的对象是后面的引用类型时,则返回true,并执行语句块;否则返回false
public class TestDynamic {
public static void main(String[] args) {
Person p = new Person("zhangfei", 30); //父类的引用指向父类的对象
p.show(); //只能调用父类自己的show()方法
System.out.println("--------------------------------");
//子类的引用指向子类的对象
Student s = new Student("guanyu", 35, 1001);
//若子类中没有重写show()方法,则调用从父类中继承下来的show()方法
//若子类中重写show()方法,则调用子类重写以后的show()方法
s.show();
System.out.println("--------------------------------");
//父类的引用指向子类的对象,形成多态的语法
//从Student向Person类型转换自动完成
Person ps = new Student("liubei", 40, 1002);
//由程序的执行结果可知,最终调用的是子类的show()方法
ps.show();
System.out.println("--------------------------------");
//使用引用ps可以直接调用Person类中的方法
System.out.println(ps.getName()); //liubei
//使用引用ps去调用Student类中的方法 ps.getId(); error
System.out.println("--------------------------------");
//ps.test(); //当使用引用调用静态方法时,产生警告信息
Person.test();//父类的test()方法
System.out.println("--------------------------------");
//当需要从父类类型向子类类型转换时, Person=>Student转换报错,需要强转
Student s2 = (Student) ps;
System.out.println(s2.getId()); //1002
//String str2 = (String)ps; error
//希望实现Person类型向Teacher类型的强转,编译阶段不报错,但运行阶段
//会产生java.lang.ClassCastException 类型转换异常
if(ps instanceof Teacher){
Teacher t = (Teacher)ps;
System.out.println("可以放心地进行强转!");
}
else
System.out.println("强转有风险,执行需谨慎!");
}
}