Java面向对象编程(二)
关键字 —— this
一、this关键字的使用:
1.this可以用来修饰、调用:属性、方法、构造器。
2.this修饰属性和方法: this理解为:当前对象 或 当前正在创建的对象。
2.1 在类的方法中,我们可以使用”this.属性”或”this.方法”的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用”this.变量”的方式,表明此变量是属性,而非形参。
2.2 在类的构造器中,我们可以使用”this.属性”或”this.方法”的方式,调用当前正在创建的对象属性或方法。 但是,通常情况下,我们都选择省略”this.”。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用”this.变量”的方式,表明此变量是属性,而非形参。
二、 this调用构造器
① 我们在类的构造器中,可以显式的使用”this(形参列表)”方式,调用本类中指定的其他构造器。
② 构造器中不能通过”this(形参列表)”方式调用自己。
③ 如果一个类中有n个构造器,则最多有 n – 1构造器中使用了”this(形参列表)”。
④ 规定:”this(形参列表)”必须声明在当前构造器的首行。
⑤ 构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器。
一、package关键字的使用
1.为了更好的实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
4.每 “.” 一次,就代表一层文件目录。
补充:同一个包下,不能命名同名的接口、类。
不同的包下,可以命名同名的接口、类。
二、import关键字的使用
1. 在源文件中显式的使用import结构导入指定包下的类、接口
2. 声明在包的声明和类的声明之间
3. 如果需要导入多个结构,则并列写出即可
4. 可以使用”xxx.*”的方式,表示可以导入xxx包下的所有结构
5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6. 如果使用的类或接口是本包下定义的,则可以省略import结构
7. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
8. 使用 “xxx.* ” 方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
9. import static:导入指定类或接口中的静态结构:属性或方法。
继承性
继承:将多个类中存在的相同属性和行为,全都放进一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
一、继承性的格式:
class 子类A extends 父类B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
二、继承的优点:
1.提高了代码的复用性:多个类相同的成员可以放到同一个类中。
2.提高了代码的维护性:如果功能的代码需要修改,修改一处即可。
3.让类与类之间产生了关系,是多态的前提。其实这也是继承的一个弊端:类的耦合性很强
设计原则:高内聚低耦合。 简单的理解: 内聚就是自己完成某件事情的能力。 耦合就是类与类之间的关系。
三、注意事项:
1.子类继承父类后就获取了直接父类以及所有间接父类中声明的所有属性和方法。所有的类除(java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
2.子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。 不要为了部分功能而去继承。
四、继承的特点
1.java类的单继承性,一个子类只能有一个父类。
2.一个类可以被多个子类继承。
3.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
super关键字
1. super代表父类存储空间的标识(引用)(可操作父类中成员)
2. super可以用来调用:属性、方法、构造器。
3. super的使用:调用属性和方法
3.1 我们可以在子类的方法或构造器中。通过使用”super.属性”或”super.方法”的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略”super.”
3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用”super.属性”的方式,表明调用的是父类中声明的属性。
3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用”super.方法”的方式,表明调用的是父类中被重写的方法。
4.super调用构造器
4.1 我们可以在子类的构造器中显式的使用”super(形参列表)”的方式,调用父类中声明的指定的构造器
4.2 “super(形参列表)”的使用,必须声明在子类构造器的首行!
4.3 我们在类的构造器中,针对于”this(形参列表)”或”super(形参列表)”只能二选一,不能同时出现
4.4 在构造器的首行,没有显式的声明”this(形参列表)”或”super(形参列表)”,则默认调用的是父类中空参的构器:super()
4.5 在类的多个构造器中,至少有一个类的构造器中使用了”super(形参列表)”,调用父类中的构造器。
注意:
1.要想初始化子类,就必须先初始化父类(也就是调用父类的构造方法)
2.super(…)和this(…)必须出现在构造方法的第一条语句上。子类中会默认
3.如果调用了多次super,相当于调用多次父类构造方法,就是对父类数据进行多次初始化
4.每个类只能初始化一次。


class Father{
int age;
public Father6(){
System.out.println("这是父类中无参构造方法");
}
public Father6(String name){
System.out.println("父类的有参构造");
}
}
class Son6 extends Father6{
public Son6(){
// this("随便给");
super("随便给");
// super();
System.out.println("子类的无参构造方法");
// this("随便给");
}
public Son6(String name){
super("随便给");
System.out.println("子类的带参数的构造方法");
}
}
public class ExtendsDemo8 {
public static void main(String[] args) {
Son6 s = new Son6();
}
super、this实例
Overload(重载) 与 Override(重写)
一、 override(方法重写)
1.定义:子类继承父类后,可以对父类中同名同参数的方法,进行覆盖操作。
2.重写的规则:
二、区别:
方法的重写:子类中出现了和父类中一模一样的方法声明,叫做重写,也被叫做方法的覆盖。
方法的重载:本类中出现了方法名一样,参数列表不一样的方法,与返回值无关的方法,叫重载。
三、注意事项:
1.父类中被private修饰的方法不能被修饰。
2.子类重写父类的方法时,访问权限不能降低。
3.父类中方法是静态的,子类重写时也必须用静态方法重写。
多态性
一、多态的定义:某一个事物,在不同时刻体现出的不同状态。
对象的多态性:父类的引用指向子类的对象
二、多态的前提:
- 要有类的继承关系。
- 要有方法的重写。
- 父类指向子类。格式:父 f = new 子();

三、多态的优点:
- 提高了程序的维护性(由继承保证)
- 提高了程序的扩展性(由多态保证)
四、多态的弊端:
- 不能通过多态去访问父类与子类同名的方法(解决方法:super关键字)
- 不能通过多态访问子类特有的方法,但是通过转换可以进行访问。
多态中强制转换有:a.向上转型:子类 变量名 = (子类)父类
b.向下转型:父→子
c.匿名对象:((子类)父类变量). 方法


虚拟方法调用(Virtual Method Invocation)
正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
虚拟方法调用(多态情况下) 子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。多态是运行时行为
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法
编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类 的getInfo()方法。——动态绑定
虚拟方法调用(Virtual Method Invocation)
面试题 : 多态是运行时行为。只有在运行时才知道new的是谁。
instanceof操作符
x instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求:1. 要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
Object类的使用
Object类是所有Java类的根父类。
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类。
Object类中的功能(属性、方法)具有通用性。
属性:无
方法:finalize(在垃圾回收之前调用,一般不主动调用,由Java中垃圾回收器自动调用)、equals()、toString()、getClass()、hashCode()、clone()
Object类知声明了一个空参的构造器。


import java.util.Date; /* * * 面试题: == 和 equals() 区别 * * 一、回顾 == 的使用: * == :运算符 * 1. 可以使用在基本数据类型变量和引用数据类型变量中 * 2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同) * 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体 * 补充: == 符号使用时,必须保证符号左右两边的变量类型一致。 * * 二、equals()方法的使用: * 1. 是一个方法,而非运算符 * 2. 只能适用于引用数据类型 * 3. Object类中equals()的定义: * public boolean equals(Object obj) { return (this == obj); } * 说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体 * * 4. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是 * 两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。 * * 5. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们 * 就需要对Object类中的equals()进行重写. * 重写的原则:比较两个对象的实体内容是否相同. */ public class EqualsTest { public static void main(String[] args) { //基本数据类型 int i = 10; int j = 10; double d = 10.0; System.out.println(i == j);//true System.out.println(i == d);//true boolean b = true; // System.out.println(i == b); char c = 10; System.out.println(i == c);//true char c1 = 'A'; char c2 = 65; System.out.println(c1 == c2);//true //引用类型: Customer cust1 = new Customer("Tom",21); Customer cust2 = new Customer("Tom",21); System.out.println(cust1 == cust2);//false String str1 = new String("atguigu"); String str2 = new String("atguigu"); System.out.println(str1 == str2);//false System.out.println("****************************"); System.out.println(cust1.equals(cust2));//false--->true System.out.println(str1.equals(str2));//true Date date1 = new Date(32432525324L); Date date2 = new Date(32432525324L); System.out.println(date1.equals(date2));//true } }
== 和 equals() 区别
toString
Object类中toString()的使用:
1. 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
2. Object类中toString()的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}


toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。
在进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date();
System.out.println(“now=”+now); 相当于System.out.println(“now=”+now.toString());
可以根据需要在用户自定义类型中重写toString()方法
如String 类重写了toString()方法,返回字符串的值。
s1=“hello”;
System.out.println(s1);//相当System.out.println(s1.toString()); 基本类型数据转换为String类型时,调用了对应包装类的toString()方法
int a=10; System.out.println(“a=”+a);
toString()方法
3. 像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回”实体内容”信息
4. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的”实体内容”
包装类(Wrapper)的使用


/*
* Java中的JUnit单元测试
*
* 步骤:
* 1.选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
* 2.创建Java类,进行单元测试。
* 此时的Java类要求:① 此类是public的 ②此类提供公共的无参的构造器
* 3.此类中声明单元测试方法。
* 此时的单元测试方法:方法的权限是public,没有返回值,没有形参
*
* 4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
*
* 5.声明好单元测试方法以后,就可以在方法体内测试相关的代码。
* 6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test(eclipse中)
*
* 说明:
* 1.如果执行结果没有任何异常:绿条
* 2.如果执行结果出现异常:红条
*/
import java.util.Date;
public class JUnitTest {
int num = 10;
@Test
public void testEquals(){
String s1 = "MM";
String s2 = "MM";
System.out.println(s1.equals(s2));
//ClassCastException的异常
// Object obj = new String("GG");
// Date date = (Date)obj;
System.out.println(num);
show();
}
public void show(){
num = 20;
System.out.println("show()....");
}
@Test
public void testToString(){//测试谁就单击选中谁
String s2 = "MM";
System.out.println(s2.toString());
}
}
Java中JUnit单元测试
一、针对八种基本数据类型定义相应的引用类型—包装类(封装类)
有了类的特点,就可以调用类中的方法,Java才是真正的面向对象
二、基本数据类型、包装类、String三者之间的转换:


import org.junit.Test;
/*
* 包装类的使用:
* 1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
*
* 2.掌握的:基本数据类型、包装类、String三者之间的相互转换
*
*
*
*/
public class WrapperTest {
//String类型 --->基本数据类型、包装类:调用包装类的parseXxx(String s)
@Test
public void test5(){
String str1 = "123";
//错误的情况:
// int num1 = (int)str1;不行
// Integer in1 = (Integer)str1;强转需要子父类之间的关系
//可能会报NumberFormatException
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
//基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)
@Test
public void test4(){
int num1 = 10;
//方式1:连接运算
String str1 = num1 + "";
//方式2:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);//"12.4"
}
/*
* JDK 5.0 新特性:自动装箱 与自动拆箱
*/
@Test
public void test3(){
// int num1 = 10;
// //基本数据类型-->包装类的对象
// method(num1);
//自动装箱:基本数据类型 --->包装类
int num2 = 10;
Integer in1 = num2;//自动装箱
boolean b1 = true;
Boolean b2 = b1;//自动装箱
//自动拆箱:包装类--->基本数据类型
System.out.println(in1.toString());
int num3 = in1;//自动拆箱
}
public void method(Object obj){
System.out.println(obj);
}
//包装类--->基本数据类型:调用包装类Xxx的xxxValue()
@Test
public void test2(){
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
//基本数据类型 --->包装类:调用包装类的构造器
@Test
public void test1(){
int num1 = 10;
// System.out.println(num1.toString());
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
Integer in2 = new Integer("123");
System.out.println(in2.toString());
//报异常
// Integer in3 = new Integer("123abc");
// System.out.println(in3.toString());
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);
Boolean b3 = new Boolean("true123");
System.out.println(b3);//false
Order order = new Order();
System.out.println(order.isMale);//false
System.out.println(order.isFemale);//null
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
基本数据类型、包装类、String三者之间的转换
三、包装类面试题:


Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);
//1.0
//解析:编译时就要求类型是一致的,int型自动转换为double类型的
包装类面试题1


public void method1() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);// false
/*
Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率
*/
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
//
Integer x = 128;//相当于new了一个对象
Integer y = 128;//相当于new了一个对象
System.out.println(x == y);//false
//
}
包装类面试题2