第四章:Java面向对象特征
4.1类的定义
- 类的声明
[public][abstract][final] class ClassName
[extends SuperClassName][implements InterfaceNameList]{
…
}
- 成员变量声明(自动初始化)
[public][protected][private][static][final]
type varibleName;
public,protected,private: 控制访问权限
static: 类变量/静态变量
final: 常量
- 成员方法声明
[public][protected][private][static][final]
return_type methodName
([<argument_list>])[throws <exception>]{<block>}
//方法中声明的变量是局部变量(显示初始化)
//方法是传值的,方法调用不会改变参数的值
//基本数据类型就是传值,对象就是传引用
-
Java 应用程序有且仅有的一种参数传递机制,即按值传递
-
关键字this
public class Hello {
String s = "Hello";
public Hello(String s){
System.out.println("s = " + s); //HelloWorld!
System.out.println("1 -> this.s = " + this.s); //Hello
this.s = s;
System.out.println("2 -> this.s = " + this.s); //HelloWorld!
}
public static void main(String[] args) {
Hello x=new Hello("HelloWorld!");
} }
//当构造方法或类成员方法中局部变量与类成员变量同名时,类成员变量将被隐藏,若在方法中需要操作类成员变量则必须使用this.
- 方法重载(在同一个类中一个方法名被用来定义多个方法)
class Screen {
public void print( int i){ … }
public void print( float i){ … }
public void print( String str ){ … }
}
//参数表(参数个数、类型)必须不同,以此区分不同方法体
//返回类型、修饰符可相同或不相同
- 类的构造方法
- 方法名必须与类名相同,不能带返回类型**(修饰符不只是public)**
- 如果在类定义中无构造函数,Java在编译时可缺省加入构造方法
- 一旦在类中有一个自己声明的带参数的构造方法,则缺省的构造方法将不被加到源程序中
- 构造函数作用:初始化成员变量
- 构造方法可以重载
- 激活重载的构造方法,在一个构造方法中可以利用另一个构造方法
class Employee{
private String name;
private int salary;
public Employee(String n, int s){
name = n ;
salary = s;
}
public Employee( String n){ this(n,0); }
public Employee( ){ this(“Unknown”); }
}
- 访问权限
- 本类中访问,实例化对象访问
- public:表明该成员变量和方法是共有的,能在任何情况下被访问
protected:必须在同一包中类或不同包中的子类才能被访问
default(默认):同一包中的类可以访问 private: 只能被自身访问和修改
4.2内部类
- 内部类是在一个类的声明里声明的类,也称为嵌套类
class A{
class B{ }
}
public class Employee {
private String id;
public void setId(String id) {
this.id = id;
}
class Manager{
String introInfo(){
return id;
}
}
}
public class Test {
public static void main(String[] args) {
Employee e = new Employee();
e.setId("20200810");
Employee.Manager m = e.new Manager();
String id = m.introInfo();
System.out.println("员工的编号:"+id);
}
}
- 内部类作用:
- 内部类可以很好的实现隐藏,也就是封装性。一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
- 内部类拥有外部类的所有元素的访问权限
- 可以实现多重继承
- 可以实现同一个类中两种同名方法的调用
- 内部类特点:
- 一个内部类的对象能够访问创建它的外部类对象的所有属性及方法
- 对于同一个包中的其它类来说,内部类能够隐藏起来(将内部类用private修饰即可)
- 内部类可定义在方法中,称为局部内部类,但它只能使用方法中的final常量
- 内部类可以被定义为抽象类
- 匿名类:匿名类在一个表达式中定义,其定义就像调用所继承父类或实现接口的构造方法,只是在构造方法后的代码块中包含了匿名类的定义
class ClassA {
void aMethod(){};
}
public class TryAnonymous {
public static void main(String[] args) {
ClassA c = new ClassA() {
void aMethod() {
System.out.println("Hello world!");
}
};
c.aMethod(); } }
- Lambda表达式
- 都可以把功能如对象一样传递给方法。匿名类确实是向方法传递了一个对象,而使用Lambda表达式不需要创建对象,只需要将Lambda表达式传递给方法
- Lambda表达式语法上更加简单,代码更少
4.3对象生命周期
- 对象实例化过程:
- 开辟内存空间,成员变量自动初始化
- 显示初始化
- 执行构造方法
- 清除对象:
- 一个对象在没有引用指向它时,可作为垃圾收集
- 显示执行: System.gc()
4.4继承与多态
-
子类的特点:
- 子类继承父类的属性、方法,子类中只需声明特有的东西
- 带private 修饰符的属性、方法不能被继承,构造方法不能被继承
- 在方法中调用构造方法用this()
- 调用父类的构造方法用super(), super 指向该关键字所在类的父类
-
java是单继承的,即只能从一个类继承,extends后类名只能有一个
- 可以用接口弥补: 用一个类实现多个接口, 达到多继承效果
-
子类对象的初始化:
- 分配空间,并初始化为“0”值
- 按继承关系从顶向下显式初始化
- 按继承关系从顶向下调用构造方法
-
方法重写(覆盖):
- 子类可以改变从父类继承的行为
- 被重写方法的返回值、方法名、参数列表要与父类中的方法完全一样
- 被重写方法的方法的访问权限不能缩小
-
向上转型:
- 向上转型对象只能调用父类中定义的方法和变量
- 向上转型对象不能操作子类新增的成员变量(失掉了这部分属性),不能使用子类新增的方法(失掉了一些功能)
- 如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法(动态连接、动态调用)
- 变量不能被重写(覆盖),重写针对方法,变量不存在重写的说法
//语法
父类类型 引用名 = new 子类类型();
class Animal{
public void info(){
System.out.println("我是动物");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗在吃东西");
}
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
animal.info(); //我是动物
}
}
- 向下转型:
- 向下转型对象可以操作父类及子类成员变量和成员方法
- 成员变量重名,调用的是子类的成员变量
- 向下转型对象访问重写父类的方法时,操作的是子类的方法
- 向下转型必须进行强制类型转换
- 向下转型必须保证父类对象引用的是该子类的对象,如果引用的是父类的其他子类对象,会抛出类型不匹配异常
- 向下转型对象可以操作父类及子类成员变量和成员方法
//语法
子类类型 引用名 = (子类类型)父类引用;
class Animal{
public void info(){
System.out.println("我是动物");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗在吃东西");
}
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
Dog animal1 = (Dog) animal; // 向下转型
animal1.eat(); //狗在吃东西
}
}
/*示例代码
* 使用对象类型的转换,根据编程提示,完成猫类和动物类的转换,以及彼此方法和属性的调用
*/
// 定义动物类
class Animal{
// 定义动物类的属性
public String name = "动物";
public static String staticName = "可爱的动物";
// 定义动物类的行为方法
public void eat() {
System.out.println("动物吃饭");
}
public static void staticEat() {
System.out.println("可爱的动物正在在吃饭");
}
}
// 定义猫类,该类继承动物类
public class Cat extends Animal{
// 定义猫类的属性
public String name = "猫";
public String str = "可爱的小猫";
public static String staticName = "我是喵星人";
// 定义猫类的行为方法
public void eat() {
System.out.println("猫吃饭");
}
public static void staticEat() {
System.out.println("喵星人在吃饭");
}
public void eatMethod() {
System.out.println("猫喜欢吃鱼");
}
public static void main(String[] args) {
// 向上转型,把猫类对象赋值给动物类
Animal ani1 = new Cat();
// 向下转型,将动物类引用转换为猫类对象
Cat ani2 = (Cat) ani1;
// 输出Animal类的name变量
System.out.println(ani1.name);//动物
// 输出Animal类的staticName变量
System.out.println(ani1.staticName);//可爱的动物
// 输出Cat类的eat()方法
ani1.eat();//猫吃饭
// 输出Animal类的staticEat()方法
ani1.staticEat();//可爱的动物正在在吃饭
// 调用Cat类的str变量
System.out.println(ani2.str);//可爱的小猫
// 调用Cat类的eatMethod()方法
ani2.eatMethod();//猫喜欢吃鱼
}
}
-
多态:指同一个名字对应着多种不同的行为或实现(方法名字共享),或不同对象收到相同的消息时产生不同的行为
-
多态使程序具有良好的可扩展性
- 编译时的多态性(静态):即方法重载
- 运行时的多态性(动态):即方法重写(覆盖)
-
Instanceof关键字
- Empolyee a = new Manager();(class Manager extends Empolyee)
则 a instanceof Manager 为true; - 向上转型、向下转型对象instanceof子类、父类对象结果均为true
- 左边是对象,右边是类,返回类型是boolean。它的具体作用是测试左边的对象是否是右边类或者该类的子类创建的实例对象
- Empolyee a = new Manager();(class Manager extends Empolyee)
-
类型转换
- 父类弱、子类强,指向父类的引用不能直接按子类引用,
必须要强制类型转换后才能作为子类的引用使用。
- 父类弱、子类强,指向父类的引用不能直接按子类引用,