面向对象的特征
目录
继承性
方法的重写
四种不同的权限修饰
super关键字
多态性
instanceof关键字
Object类的使用
JUnit单元测试
包装类(Wrapper)的使用
static关键字
理解main方法的语法
类的成员之四:代码块
final关键字
抽象类与抽象方法
接口(interface)
类的成员之五:内部类
1.继承性
继承(extends):public class 子类 extends 父类
Ctrl+T 查看继承结构
1.1 体现:一旦子类A继承父类B之后,子类A中就获取到了父类B中声明的结构、属性和方法
特别的,父类中声明为private的属性和方法,子类继承父类之后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
示例:
public class A extends B{}
**1.2 **子类继承父类之后,还可以声明自己特有的属性和方法,实现功能的拓展
1.3 子类和父类的关系:不同于子集和集合的关系
extends:延展 拓展
1.4 java中关于继承性的规定:
- 一个子类只能有一个父类
- **Java中类的单继承性:**一个类只能有一个父类
- 子父类是相对的概念
- 子类直接继承的 父类,称为直接父类;同理,间接继承的父类称为间接父类
1.5
- 如果没有显示的声明一个类的父类的话,此类继承于java.lang.Object类
- 所有的java类(除java.lang.Object类之外)都直接或间接继承于java.lang.Object类
继承性的好处
-
减少代码冗余,提高代码复用性
-
便于功能拓展
-
为多态的使用提供前提
2.方法的重写
概念
-
重写:子类继承父类之后,可以对父类中同名参数的方法,进行覆盖操作
-
应用: 重写之后,当创建子类对象,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法
-
重写的规定:
方法的声明:
权限修饰符 返回类型 方法名(形参列表){ //方法体 }
要求:
-
重写和被重写的方法名、形参列表要相同
-
子类重写的方法权限修饰符不小于父类被重写的方法权限修饰符
>特殊情况:子类不能重写父类中声明为private权限的方法
-
返回值类型:
>父类被重写的方法返回值类型是void,则子类重写的方法返回值类型只能是void
>父类被重写的方法返回值类型是A类型,则子类重写的方法返回值类型可以是A类或A类的子类
>父类被重写的方法返回值类型是基本数据类型(比如double),则子类重写的方法返回值类型必须是相同的基本数据类型
-
子类重写的方法抛出异常类型不大于父类被重写的方法
子类和父类中的同名同参数的方法要么都声明为非static的,要么都声明为static的(不是重写)
-
重载(Overload)和重写(Override)的区别:
方法的重载和重写都是实现多态的方式
区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。
重载对返回类型没有特殊的要求,不能根据返回类型进行区分
3.四种不同的权限修饰
4.super关键字
(1)理解
- super可以理解为:父类的
- super可以用来调用属性、方法、构造器
(2)使用方法
super.属性
super.方法
//显示调用父类中声明的属性或者方法
(3)使用情景
- 子类和父类中定义了同名属性,想在子类中调用父类中生命的属性时,super.属性
- 子类重写了父类的方法之后,调用父类中被重写的方法时,super.方法
(4)super调用构造器
- 4.1 可以在子类的构造器中显式使用**“super(形参列表)”**的方式,调用父类中声明的指定构造器
- 4.2 **“super(形参列表)”**的使用,必须声明在子类的首行!
- 4.3 类的构造器中,针对**“this(形参列表)”或“super(形参列表)”**只能二选一,不能同时出现
- 4.4 在构造器的首行,没有显示声明“this(形参列表)”和“super(形参列表)”,则默认调用父类中空参构造器super()
- 4.5 在类的多个构造器中 至少有一个类中使用了“super(形参列表)”,调用父类中的构造器
(5)super调用构造器需要注意
- this(形参列表): 本类重载的其他的构造器
- super(形参列表): 调用父类中指定的构造器
5.多态性
(1)多态:父类的引用指向子类的对象(子类的对象赋给父类的引用)
理解:可以理解为一个事物的多种形态,可以直接用在抽象类和接口上
(2)多态的使用:当调用子父类同名同参数的方法,实际执行的是子类重写父类的方法–虚拟方法调用
有了对象的多态性之后,编译期只能调用父类中声明的方法,但运行期实际执行的是子类重写父类的方法
总结:编译看左,运行看右
前提:(1)类的继承关系 (2)方法的重写
(3)对象的多态性只适用于方法,不适用于属性(编译和运行都看左边)
(4)重载和多态的区别:
6.instanceof关键字
功能:实现父类调用子类特有属性和方法时的向下转型
使用方法 a instanceof A: 判断对象a是否是类A的实例。是 返回true;不是 返回false
使用情景:为了避免在向下转型时出现ClassCastException异常,所以要先进行instanceof判断,true则向下转型
public class Person extends Object {...}
public class Student extends Person {...}
public class Graduate extends Person {...}
public void method1(Person e) {
if (e instanceof Person)
// 处理Person类及其子类对象
if (e instanceof Student)
//处理Student类及其子类对象
if (e instanceof Graduate)
//处理Graduate类及其子类对象
}
7.Object类的使用
**定义:**Object类是所有Java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类
为java.lang.Object类
public class Person {...}
//等价于:
public class Person extends Object {...}
//例:
method(Object obj){...} //可以接收任何类作为其参数
Person o=new Person();
method(o);
常用方法:
-
equals方法
/* *equals():所有类都继承了Object,也就获得了equals()方法。还可以重写。 *只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。 */ //格式: obj1.equals(obj2) /*特例:当用equals() 方法进行比较时,对类File 、String 、Date 及包装类(Wrapper Class)来说, *是比较类型及内容而不考虑引用的是否是同一个对象; *当自定义使用equals()时,可以重写。用于比较两个对象的“内容”是否都相等 */
==和equals的区别(面试)
toString()方法
toString()方法在Object类中定义,其返回值是String类型,返回类名和它
的引用地址。在进行String与其它类型数据的连接操作时,自动调用toString()方法
Object类中tostring()的定义:
public String ToStringTest(){
return getClass().getname() + "@" + Integer.toHexString(hashCode());
}
8.JUnit单元测试
步骤
-
选中当前工程 - 右键选择:build path -add libraries - JUnit 4 - 下一步
-
创建Java类,进行单元测试
此时的Java类要求:① 此类是public的 ② 此类提供公共的无参构造器 此类中声明单元测试方法
-
此类中声明单元测试方法
此时的单元测试方法:方法的权限是public,没有返回值,没有形参
-
此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
-
声明好单元测试方法之后,就可以在方法体内测试相关的代码
-
写完代码以后,左键双击单元测试方法名,右键:run as -Junit Test
说明:
- 如果执行结果无异常:绿条
- 如果执行结果有异常:红条
9.包装类(Wrapper)的使用
总结:基本类型、包装类与String类间的转换
用法举例
int i = 500;
Integer t = new Integer(i);
//装箱:包装类使得一个基本数据类型的数据变成了类。
//有了类的特点,可以调用类中的方法。
String s = t.toString(); // s = “500“,t是类,有toString方法
String s1 = Integer.toString(314); // s1= “314“ 将数字转换成字符串。
String s2=“4.56”;
double ds=Double.parseDouble(s2); //将字符串转换成数字
//包装类在实际开发中用的最多的在于字符串变为基本数据类型
String str1 = "30" ;
String str2 = "30.3" ;
int x = Integer.parseInt(str1) ; // 将字符串变为int型
float f = Float.parseFloat(str2) ; // 将字符串变为int型
10.static关键字
static: 静态的
(1)使用范围
在Java类中,可用static修饰**属性、方法、代码块、内部类**
(2)使用static修饰属性:静态变量
2.1 属性按是否使用static修饰分为:静态属性 vs 非静态属性**(实例变量)**
实例变量:创建的类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的 非静态属性时,不会导致其他对象中同样的属性值的修改
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时, 会导致其他对象调用此静态变量时,是**修改过**了的。
2.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载,可通过**“类.静态变量”**的方式进行调用
② 静态变量的加载要早于对象的创建
③ 由于类只会加载一次,则静态变量在内存中也会存在一份(加入缓存):存在方法区的静态域中
④ 类变量与实例变量
内存解析
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
静态属性举例: System.out;Math.PI;
class Chinese{
//非静态变量必须先构造对象才能调用
String name;
int age;
static String nation;//静态变量 可直接以Chinese.nation调用而不用造对象
}
(3)使用static修饰方法:静态方法
① 随着类的加载而加载,可以通过**“类.静态方法”**的方式进行调用
②静态方法与非静态方法
静态方法 | 非静态方法 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
③静态方法中,只能调用静态方法或属性
非静态方法中,既可以调用非静态方法的方法或属性,也可以调用静态的方法属性
(4) static注意点
4.1 在静态的方法内,不能使用this关键字、super关键字
4.2 关于静态属性和静态方法的使用,可以从生命周期的角度理解
(5) 开发中,如何确定一个属性、方法是否要声明为static的?
>属性是可以被多个对象共享的,不会随着对象的不同而不同的
>类中的常量也常声明为static
>操作静态属性的方法,通常设置为static的
>工具类中的方法,习惯上声明为static的。比如:Math、Arrays、Collections
static应用举例
//static关键字的应用
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle(3.4);
System.out.println("c1的id:" + c1.getId() );
System.out.println("c2的id:" + c2.getId() );
System.out.println("c3的id:" + c3.getId() );
System.out.println("创建的圆的个数为:" + Circle.getTotal());
}
}
class Circle{
private double radius;
private int id;//自动赋值
public Circle(){
id = init++;
total++;
}
public Circle(double radius){
this();
// id = init++;
// total++;
this.radius = radius;
}
private static int total;//记录创建的圆的个数
private static int init = 1001;//static声明的属性被所有对象所共享
public double findArea(){
return 3.14 * radius * radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public int getId() {
return id;
}
public static int getTotal() {
return total;
}
}
单例设计模式
/*
* 单例设计模式:
* 1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
*
* 2. 如何实现?
* 饿汉式 vs 懒汉式
*
* 3. 区分饿汉式 和 懒汉式
* 饿汉式:
* 坏处:对象加载时间过长。
* 好处:饿汉式是线程安全的
*
* 懒汉式:好处:延迟对象的创建。
* 目前的写法坏处:线程不安全。--->到多线程内容时,再修改
*
*
*/
public class SingletonTest1 {
public static void main(String[] args) {
// Bank bank1 = new Bank();
// Bank bank2 = new Bank();
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);
}
}
//饿汉式
class Bank{
//1.私有化类的构造器
private Bank(){
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共的静态的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
//懒汉式
public class SingletonTest2 {
public static void main(String[] args) {
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);
}
}
class Order{
//1.私有化类的构造器
private Order(){
}
//2.声明当前类对象,没有初始化
//4.此对象也必须声明为static的
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
if(instance == null){
instance = new Order();
}
return instance;
}
}
11.理解main方法的语法
- main()方法作为程序的入口
- main()方法也是一个普通的静态方法
- main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
public class MainTest {
public static void main(String[] args) {//入口
Main.main(new String[100]);
MainTest test = new MainTest();
test.show();
}
public void show(){
}
}
class Main{
public static void main(String[] args) {
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
12.类的成员之四:代码块
13.final关键字
14.抽象类与抽象方法
15.接口(interface)
16.类的成员之五:内部类