十六、方法、类、对象、访问权限
十七、java继承和多态
同一个类中,一个方法调用另一个方法,如果对方不是static修饰,必须用对象调用,但是java允许省略不写,及可以省略this
static修饰的方法不能使用this关键字,也不能调用非static修饰的方法、变量
参数名和成员变量明相同时使用this关键字来代表
this()方法只能用在构造方法内,且必须是第一条语句,表示本类的构造方法
对象创建:
显示创建:
new创建
类名 对象名 = new 类名();
使用 new 关键字或 Class 对象的 newInstance() 方法创建对象时,都会调用类的构造方法
调用 java.lang.Class 或者 java.lang.reflect.Constuctor 类的 newlnstance() 实例方法
java.lang.Class Class 类对象名称 = java.lang.Class.forName(要实例化的类全称);
类名 对象名 = (类名)Class类对象名称.newInstance();
使用 Class 类的 newInstance() 方法创建对象时,会调用类的默认构造方法,即无参构造方法。
调用对象的 clone() 方法
类名对象名 = (类名)已创建好的类对象名.clone();
使用 Object 类的 clone() 方法创建对象时,不会调用类的构造方法,它会创建一个复制的对象,这个对象和原来的对象具有不同的内存地址,但它们的属性值相同。
如果类没有实现 Cloneable 接口,则 clone。方法会抛出 java.lang.CloneNotSupportedException 异常,所以应该让类实现 Cloneable 接口。
隐式创建:
无论釆用哪种方式创建对象,Java 虚拟机在创建一个对象时都包含以下步骤:
注意:每个对象都是相互独立的,在内存中占有独立的内存地址,并且每个对象都具有自己的生命周期,当一个对象的生命周期结束时,对象就变成了垃圾,由 Java 虚拟机自带的垃圾回收机制处理。
java匿名对象
一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用。
public static void main(String[] args) {
new Person("张三", 30).tell(); // 匿名对象
}
对象的销毁:
对象使用完之后需要对其进行清除。对象的清除是指释放对象占用的内存。在创建对象时,用户必须使用 new 操作符为对象分配内存。不过,在清除对象时,由系统自动进行内存回收,不需要用户额外处理。这也是 Java 语言的一大特色,某种程度上方便了程序员对内存的管理。
Java 语言的内存自动回收称为垃圾回收(Garbage Collection)机制,简称 GC。垃圾回收机制是指 JVM 用于释放那些不再使用的对象所占用的内存。
Java 语言并不要求 JVM 有 GC,也没有规定 GC 如何工作。不过常用的 JVM 都有 GC,而且大多数 GC 都使用类似的算法管理内存和执行回收操作。具体的垃圾回收实现策略有好多种,在此不再赘述。
一个对象被当作垃圾回收的情况主要如下两种。
1)对象的引用超过其作用范围。
{
Object o = new Object(); // 对象o的作用范围,超过这个范围对象将被视为垃圾
}
2)对象被赋值为 null。
{
Object o = new Object();
o = null; // 对象被赋值为null将被视为垃圾
}
在 Java 的 Object 类中还提供了一个 protected 类型的 finalize() 方法,因此任何 Java 类都可以覆盖这个方法,在这个方法中进行释放对象所占有的相关资源的操作。
在 Java 虚拟机的堆区,每个对象都可能处于以下三种状态之一。
1)可触及状态:当一个对象被创建后,只要程序中还有引用变量引用它,那么它就始终处于可触及状态。
2)可复活状态:当程序不再有任何引用变量引用该对象时,该对象就进入可复活状态。在这个状态下,垃圾回收器会准备释放它所占用的内存,在释放之前,会调用它及其他处于可复活状态的对象的 finalize() 方法,这些 finalize() 方法有可能使该对象重新转到可触及状态。
3)不可触及状态:当 Java 虚拟机执行完所有可复活对象的 finalize() 方法后,如果这些方法都没有使该对象转到可触及状态,垃圾回收器才会真正回收它占用的内存。
注意:调用 System.gc() 或者 Runtime.gc() 方法也不能保证回收操作一定执行,它只是提高了 Java 垃圾回收器尽快回收垃圾的可能性。
访问控制符
private:同类
friendly:同包
protected:同包或异包子类
public:同包、异包
访问范围 | private | friendly(默认) | protected | public |
---|---|---|---|---|
同一个类 | 可访问 | 可访问 | 可访问 | 可访问 |
同一包中的其他类 | 不可访问 | 可访问 | 可访问 | 可访问 |
不同包中的子类 | 不可访问 | 不可访问 | 可访问 | 可访问 |
不同包中的非子类 | 不可访问 | 不可访问 | 不可访问 | 可访问 |
static关键字:
this关键字和super关键字都和类的特定实例相关
final关键字:
可变参数列表:
methodName({paramList},paramType…paramName)
中括号实际开发中不存在,只能有一个可变参数(同种类型的形式参数可以有任意多个),且只能放在最后
构造方法:无参数的构造方法也被称为 Nullary 构造方法。只有编译程序自动加入的构造方法,才称为默认构造函数。如果自行编写无参数、没有内容的构造函数,就不称为默认构造函数了(只是 Nullary 构造函数)。虽然只是名词定义,不过认证考试时要区别一下两者的不同。
析构方法:析构方法与构造方法相反,当对象脱离其作用域时(例如对象所在的方法已调用完毕),系统自动执行析构方法。析构方法往往用来做清理垃圾碎片的工作,例如在建立对象时用 new 开辟了一片内存空间,应退出前在析构方法中将其释放。
在 Java的 Object 类中还提供了一个 protected 类型的 finalize() 方法,因此任何 Java 类都可以覆盖这个方法,在这个方法中进行释放对象所占有的相关资源的操作。
对象的 finalize() 方法具有如下特点:
包:
Java 包的命名规则如下:
有冲突使用类全名
java常用系统包:
包 | 说明 |
---|---|
java.lang | Java 的核心类库,包含运行 Java 程序必不可少的系统类,如基本数据类型、基本数学函数、 字符串处理、异常处理和线程类等,系统默认加载这个包 |
java.io | Java 语言的标准输入/输出类库,如基本输入/输出流、文件输入/输出、过滤输入/输出流等 |
java.util | 包含如处理时间的 Date 类,处理动态数组的 Vector 类,以及 Stack 和 HashTable 类 |
java.awt | 构建图形用户界面(GUI)的类库,低级绘图操作 Graphics 类、图形界面组件和布局管理 (如 Checkbox 类、Container 类、LayoutManger 接口等),以及用户界面交互控制和事 件响应(如 Event 类) |
java.awt.image | 处理和操纵来自网上的图片的 Java 工具类库 |
java.wat.peer | 很少在程序中直接用到,使得同一个 Java 程序在不同的软硬件平台上运行 |
java.net | 实现网络功能的类库有 Socket 类、ServerSocket 类 |
java.lang.reflect | 提供用于反射对象的工具 |
java.util.zip | 实现文件压缩功能 |
java.awt.datatransfer | 处理数据传输的工具类,包括剪贴板、字符串发送器等 |
java.sql | 实现 JDBC 的类库 |
java.rmi | 提供远程连接与载入的支持 |
java. security | 提供安全性方面的有关支持 |
public class Student extends Person{}
只能单继承,父类的private对子类不可见,子类会调用父类的构造方法
通过引用类型变量来访问所引用对象的属性和方法时,Java 虚拟机将采用以下绑定规则:
说白了,动态绑定只发生在,实例方法和引用变量实际引用的对象的方法之间,其他的都是静态绑定,都是父类的方法、变量。
向上转型:
fatherClass obj = new sonClass();
向下转型:
sonClass obj = (sonClass) fatherClass;
在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖。
在重写方法时,需要遵循下面的规则:
另外还要注意以下几条:
多态性是面向对象编程的又一个重要特征,它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。
对面向对象来说,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。
java实现多态有 3 个必要条件:继承、重写和向上转型
在 Java 中可以使用 instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例
boolean result = obj instanceof Class
如果 object 是 class 的一个实例,则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例,或者 object 是 null,则返回 false。class可以是类,可以是接口。
instanceof在Java的编译状态和运行状态是有区别的:
在编译状态中,class可以是object对象的父类,自身类,子类。在这三种情况下Java编译时不会报错。
在运行转态中,class可以是object对象的父类,自身类,不能是子类。在前两种情况下result的结果为true,最后一种为false。但是class为子类时编译不会报错。运行结果为false。 (大致就是判断表达式:class 变量=(class)object的引用 是否成立)。
object instanceof class中,object 是看它实际引用的对象。
如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类称为抽象类
<abstract>class<class_name> {
<abstract><type><method_name>(parameter-iist);
}
abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中
抽象类的定义和使用规则如下:
接口比抽象类更加抽象,因为其中的成员变量为全局静态常量,方法为公共抽象方法,都是public的
[public] interface interface_name [extends interface1_name[, interface2_name,…]] {
// 接口体,其中可以包含定义常量和声明方法
[public] [static] [final] type constant_name = value; // 定义常量
[public] [abstract] returnType method_name(parameter_list); // 声明方法
}
一般不用声明public、static、final ,都是隐式的,不能实例化
所有的抽象方法必须被重写,否则新类要定义为抽象类
implements来实现接口,可以多实现,但只能单继承,继承在前,实现在后
.class
文件,但是前面冠以外部类的类名和$
符号。实例内部类:
在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。
Inner1 i = new Outer().new inner1();//实例化方法
在实例内部类中,可以访问外部类的所有成员。
在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。
静态内部类:
局部内部类:
匿名内部类:
new <类或接口>() {
// 类的主体
};
匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。(Java8新特性允许了)
匿名类中允许使用非静态代码块进行成员初始化操作。
匿名类的非静态代码块会在父类的构造方法之后被执行。
(参数列表) -> {
// Lambda表达式体
}
/**
->被称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:
左侧:Lambda 表达式的参数列表。
右侧:Lambda 表达式中所需执行的功能,用{ }包起来,即 Lambda 体。
*/
必须是函数式接口才可以使用Lambda表达式(及一个接口中,有且只有一个抽象的方法(Object 类中的方法不包括在内))。
Java 8 提供了一个声明函数式接口注解 @FunctionalInterface
// 可计算接口
@FunctionalInterface
public interface Calculable {
// 计算两个int数值
int calculateInt(int a, int b);
}
在接口之前使用 @FunctionalInterface 注解修饰,那么试图增加一个抽象方法时会发生编译错误。但可以添加默认方法和静态方法。
原文:https://www.cnblogs.com/namusangga/p/14613666.html