Java【第七篇】面向对象之类设计
Java类的继承
可以让一个类继承自另一个类,此时该类会继承另一个类中的属性和方法,这样可以少写很多代码
类继承语法规则
< 修饰符> class < 子类名称> [extends < 父类>]
{
<属性和方法的声明>
}
类的继承
子类继承了父类,就继承了父类的方法和属性。(子类对象可以调用父类属性、方法)
在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。
因而,子类通常比父类的功能更多,而是对父类的“扩展”。
在Java中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”。
继承规则
Java只支持单继承,不允许多重继承
一个子类只能有一个父类
一个父类可以派生出多个子类
子类不能继承父类中私有的(private)的成员变量和方法,不能直接访问【可以调用父类的public或者protect方法去访问】
示例
父类
package com.uncleyong; import java.util.Date; public class Person {
public String name;
public int age;
public Date birth; private String lover = "lucy"; public String getInfo(){
return "name: " + name + ", " +
"age: " + age + ", " +
"birth: " + birth+ ", " +
"lover: " + lover;
} }
子类
package com.uncleyong; public class Student extends Person{
public String school;
}
测试类
package com.uncleyong; import java.util.Date; public class TestPerson {
public static void main(String[] args) {
Student student = new Student();
student.name = "Jerry";
student.birth = new Date();
student.age = 1;
student.school = "清华";
System.out.println(student.getInfo()); Person person = new Person();
person.age = 1;
person.birth = new Date();
person.name = "Tom"; System.out.println(person.getInfo());
}
}
访问控制
可以对Java类中定义的属性和方法进行访问控制----规定不同的保护等级: public、protected、default、private
default就是什么都不加
子类,就是可以跨包【因为子类可能跨包,所以,为了使父类中属性、方法在子类能访问,父类最严格的访问控制只能是protected】
//仅在类的内部可以访问.
private String email; //在同一个包内该属性可以被访问.
String major; //在子类中该属性可以被访问, 且该子类可以跨包(不在同一个包下)
//如果不是子类,跨包不能访问;如果不是子类,在同一个包下的类,也可以访问
protected int salary; //访问权限最高, 无论是否在一个包内, 无论是否是子类都可以被访问.(在一个项目中都可以被访问)
public String name;
public int age;
public Date birth;
方法的重写、覆盖
在子类中可以根据需要对从父类中继承来的方法(构造方法不能被继承)进行改造—覆盖方法(方法的重置、重写),在程序执行时,子类的方法将覆盖父类的方法。
覆盖方法必须和被覆盖方法具有相同的方法名称、参数列表和返回值类型。【返回类型、方法名、参数列表必须完全相同,应用场景:继承,父类的成员方法只能被它的子类重写】
如果参数个数不一样,就是方法的重载了(一个从父类继承的,一个自己类里写的,会根据调用方法时的传参,确定是调继承的,还是自己类里的),但是重载是不是要在一个类中的方法呢?【结果验证:可以在不同的类中,比如父类,虽然一个是父类,但是子类继承了,子类也就有了父类的方法】,见下面验证示例:
返回值类型必须一样,否则两个方法不知道该调用哪个(一个从父类继承的,一个自己类里写的),方法名、参数列表都一样了,只有返回类型不一样,编译的时候报错返回类型不兼容
覆盖方法不能使用比被覆盖方法更严格的访问权限。
参数个数不一样,验证:
父类:Test.java
package com.test; public class Test {
public int i;
public void t(){
System.out.println("test");
}
}
子类:Test2.java
package com.test; public class Test2 extends Test{
public void t(String s){ // 这个方法和父类t方法相比,多了一个形参,所以不是方法重写,而是方法重载
System.out.println(s);
}
public static void main(String[] args) {
Test2 test2 = new Test2();
test2.t("qzcsbj"); // qzcsbj
test2.t(); // test
}
}
关于构造方法的重载、重写
父类构造方法不能被子类继承:因为如果子类继承了父类的构造方法,父类的构造在子类中不符合构造方法的规则,也不符合一般方法的规则,因为父类的构造在子类中没有返回类型,方法名也与子类的类名不相同。不符合java语法规范。继承就跟我们现实中的父子关系差不多,要有一个孩子对象那么就得先有一个父亲<会调用父类的构造方法>,所以会执行父类构造方法。另一种如果你想调用父类的带参数构造方法,那还得通过super关键字来调用<super后面括号中加上参数;如果父类构造是无参的,子类也默认调了,在子类的默认构造方法中有一句super();>。构造方法是不能继承的,想想如果能继承,那不是孩子也能构造父亲了;见下方验证示例
父类构造方法不能被子类重写(因为不能继承);
父类构造方法不能被子类重载(因为不能继承,子类就不具有这个方法;在java中类的构造函数与类的名称相同,不可能子类和父类使用相同的类名称,因此子类也就不能重载父类的构造函数,但子类可以通过super来调用父类的构造函数);
子类可以重载从父类继承过来的方法;
子类可以重载自己默认的构造方法;
子类可以重载父类的非构造方法:可以这样理解,子类继承了父的方法,子类本身也就有了这个方法。在子类写一个只多了一个参数其余都一样的方法,就是重载了继承的这个方法,实际也是在一个类中。
父类构造方法不能被子类继承,验证:
父类:A.java
package com.qzcsbj; public class A {
public A(){
System.out.println("父类构造方法");
}
public void test(){
System.out.println("父类A测试方法");
}
}
子类:B.java
package com.qzcsbj; public class B extends A {
public int age;
public B(){
System.out.println("子类构造方法");
}
public void test(int a){
System.out.println("子类B测试方法");
} public static void main(String[] args) {
B b = new B();
b.test();
b.test(1);
}
}
输出结果:
父类构造方法
子类构造方法
父类A测试方法
子类B测试方法
上面说明:父类中的构造方法是不能继承的,但是在实例化子类的时候会调用父类的构造方法,每个子类构造方法的第一条语句,都是隐含地调用super()
重写示例
package com.uncleyong; /**
* 定义一个ManKind类,包括
* 成员变量 int sex 和 int salary;
* 方法 void manOrWorman():根据sex的值显示“man”(sex==1)或者“women”(sex==0);
* 方法 void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
*/
public class ManKind { int sex;
int salary; public void manOrWoman(){
if(sex == 0){
System.out.println("woman");
}else if(sex == 1){
System.out.println("man");
}
} public void employeed(){
if(salary != 0){
System.out.println("job");
}else{
System.out.println("no job");
}
} }
package com.uncleyong; /**
* 定义类 Kids1 继承ManKind,并包括
* 成员变量 int yearsOld;
* 方法 printAge() 打印 yearsOld 的值。
*
* 在Kids1中重新定义employed() 方法,覆盖父类ManKind中定义的employed()方法,
* 输出“Kids should study and no job.”
*/
public class Kids1 extends ManKind { int yearsOld; void printAge(){
System.out.println("yearsOld: " + yearsOld);
} // 方法重写
public void employeed() {
System.out.println("Kids should study and no job.");
} //在Kids1类的main方法中实例化Kids1的对象 someKid,用该对象访问其父类的成员变量及方法。
public static void main(String[] args) {
Kids1 someKid = new Kids1();
someKid.sex = 1;
someKid.salary = 5000;
someKid.yearsOld = 25; someKid.manOrWoman();
someKid.employeed();
someKid.printAge();
}
}
super 关键字
super的功能
在Java类中使用super来引用父类的成分:
super可用于访问父类中定义的属性
super可用于调用父类中定义的成员方法(如下例子)
super可用于在子类构造方法中调用父类的构造方法
super的追溯不仅限于直接父类
例子:子类重写的方法中,调用父类中被重写的方法,需要用super
下面子类重写父类方法,会死循环(循环调用自己),导致栈溢出
package com.uncleyong; public class Person {
private String country = "China"; public String getInfo(){
return "country:" + country;
}
}
public class Student extends Person{
private String school = "清华大学"; @Override
public String getInfo() {
return getInfo() + ", school:" + school; // 正确写法return this.getInfo() + ", school:" + school;
}
}
package com.uncleyong; public class Test {
public static void main(String[] args) {
Student student = new Student();
student.getInfo();
}
}
构造方法不能继承
子类继承父类所有的成员变量和成员方法,但不继承父类的构造方法
在一个Java类中可以通过两种方式获得构造方法:
使用系统默认的无参数构造方法
显式定义一个或多个构造方法
一旦显式定义了构造方法,则系统不再提供默认构造方法
调用父类构造方法
在子类的构造方法中可使用super(参数列表)语句调用父类的构造方法;
如果子类的构造方法中没有显示地调用父类构造方法,也没有使用this关键字调用重载的其它构造方法(调用子类中重载子类的构造方法),则系统默认调用父类无参数的构造方法【可以在这个无参构造方法体中写内容,但是不能有参数】,见下方验证;
如果子类构造方法中既未显式调用父类构造方法,而父类中又没有无参的构造方法,则编译出错;
子类的构造方法中一定要用super方式调用父类的某一个构造方法,可以通过this间接方式调当前类的某一个构造方法(这个构造方法又通过super去调了父类的一个构造方法)
间接方式
子类构造方法中第一行this调用重载的构造方法,被调用的那个重载构造方法中第一行super调用父类构造方法
直接方式
子类构造方法中第一行直接super调用父类构造方法 父类只有有参构造
方案一:子类的构造方法中第一行用super调用父类有参构造方法
方案二:父类新增无参构造方法 父类中同时存在有参和无参构造方法:
子类的构造方法的第一行可以调用父类的有参构造方法,
也可以不调用(这样就默认调用父类无参构造方法):如果子类的构造方法中没有显示地调用父类构造方法,也没有使用this关键字调用重载的其它构造方法【调用子类中重载子类的构造方法】,则系统默认调用父类无参数的构造方法【可以在这个无参构造方法体中写内容,但是不能有参数】 super(…)和this(…)调用语句不能同时在一个构造函数中出现 super(…)或this(…)调用语句只能作为构造函数中的第一句出现
验证:子类调用父类构造函数
系统默认提供无参构造函数
public Animal(){
}
也可以自己在无参构造方法体中加内容,子类也可以调这个无参方法
public Animal(){
System.out.println("父类无参构造方法");
}
父类
public class Animal {
private String name;
private int age; public Animal(){
System.out.println("父类无参构造方法");
} // public Animal(String name){
// this.name = name;
// System.out.println("父类有参构造方法,形参name: " + name);
// } public String getInfor(){
return "name: " + name;
}
}
子类
public class Cat extends Animal {
private String sex; // public Cat(){
// super("tom");
// }
}
测试类
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println(cat.getInfor());
}
}
结果
如果父类有参构造方法,那么,可以两个解决方案:
方案一:如果父类只有有参构造方法,需要在子类的构造方法的第一行调用父类的有参构造方法
父类
public class Animal {
private String name;
private int age; // public Animal(){
// System.out.println("父类无参构造方法");
// } public Animal(String name){
this.name = name;
System.out.println("父类有参构造方法,形参name: " + name);
} public String getInfor(){
return "name: " + name;
}
}
子类
public class Cat extends Animal {
private String sex; public Cat(){
super("tom");
}
}
测试类
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println(cat.getInfor());
}
}
结果
方案二:父类中同时存在有参和无参构造方法,子类的构造方法的第一行可以调用父类的有参构造方法,也可以不调用(这样就默认调用父类无参构造方法)
如果子类的构造方法中没有显示地调用父类构造方法,也没有使用this关键字调用重载的其它构造方法【调用子类中重载子类的构造方法】,则系统默认调用父类无参数的构造方法【可以在这个无参构造方法体中写内容,但是不能有参数】
父类
public class Animal {
private String name;
private int age; public Animal(){
System.out.println("父类无参构造方法");
} public Animal(String name){
this.name = name;
System.out.println("父类有参构造方法,形参name: " + name);
} public String getInfor(){
return "name: " + name;
}
}
子类
public class Cat extends Animal {
private String sex; // public Cat(){
// super("tom");
// }
}
测试类
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println(cat.getInfor());
}
}
子类对象实例化过程
示例
根据下图实现类。在TestCylinder类中创建Cylinder类的对象,设置圆柱的底面半径和高,并输出圆柱的体积,下面是uml图
父类
package com.uncleyong; public class Circle { protected double radius; public Circle() {
this.radius = 1;
System.out.println("父类构造方法");
} public double getRadius() {
return radius;
} public void setRadius(double radius) {
this.radius = radius;
} public double findArea(){
return 3.14 * radius * radius;
} }
子类
package com.uncleyong; public class Cylinder extends Circle{ private double length; public Cylinder() {
this.length = 1;
} public double getLength() {
return length;
} public void setLength(double length) {
this.length = length;
} /**
* 返回圆柱的体积
* @return
*/
public double findVolume(){
return super.findArea() * length; // 这里要加super表示调父类的,不加super表示调本类中的findArea方法
} /**
* 返回圆柱的表面积
*/
@Override
public double findArea() {
return super.findArea() * 2 + 2 * 3.14 * radius * length;
} }
测试类
package com.uncleyong; public class TestCylinder { public static void main(String[] args) { Cylinder cylinder = new Cylinder(); cylinder.setLength(2); //返回表面积
System.out.println(cylinder.findArea());
//返回体积
System.out.println(cylinder.findVolume());
} }
多态性及其应用
多态性
在Java中,子类的对象可以替代父类的对象使用(父类类型的引用变量可以指向子类的对象)
一个变量只能有一种确定的数据类型
一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中新添加的属性和方法(子类有父类没有的属性和方法)
Student m = new Student();
m.school = “pku”; //合法,Student类有school成员变量
Person e = new Student();
e.school = “pku”; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
虚拟方法调用(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()方法。—— 动态绑定
在多态的情况下,调了父类的某个方法,但是这个方法被子类重写了,运行时,其实调的是子类重写的方法。【对象是子类的,所以调子类方法】
instanceof 操作符
如果下面p2要访问子类的属性和方法,需要把父类的实例变量p2强制转换为子类类型
Person p2 = new Man();
System.out.println(((Man) p2).school);
((Man) p2).work();
Woman w2 = (Woman)p2; // 强制转换成女人,编译的时候可以过,因为p2是人,运行的时候不能过,因为运行时发现p2是男人
x instanceof A:检验x(x指向的对象)是否为类A的对象,返回值为boolean型。
要求x所属的类(x这个句柄的类型)与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B,x instanceof A值也为true。
使用 instanceof 运算符. 注意, 使用 instanceof 运算符, 必须要求前面的引用指向的变量和后边的类之间存在父子关系【前面<=后面就返回true】
总结:
instanceof前后必须有继承关系,不管哪个继承哪个,否则类型不兼容报错
如果前面继承后面,结果为true
如果前面等于后面,结果为true
如果后面继承前面,结果为false
总之,有继承关系时,前面<=后面,就返回true
示例:
Boy b = new Boy();
System.out.println(">>>>>>>>>>>>>>>>");
// Boy继承了Student
// System.out.println(b instanceof Student); // true;如果Boy没有继承Student,报类型不兼容错误
// Boy2继承了Boy
System.out.println(b instanceof Boy2); // false,因为b不是Boy2的对象
System.out.println(b instanceof Boy); // true,因为b是Boy的对象
// Boy2继承了Boy
Boy2 b2 = new Boy2();
System.out.println(b2 instanceof Boy); // true,因为b2是Boy的对象
实例2
public class TestPerson {
public static void main(String[] args) {
//多态 //1. 创建一个 Man 的实例
Man m1 = new Man(); //2. 创建一个 Woman 的实例
Woman w1 = new Woman(); //3. 创建一个 Person 的实例
Person p1 = new Person();
/**
* 多态: 在Java中,父类的引用可以指向子类的对象.【子类的对象可以替代父类的对象使用】
* 1. 在多态情况下, 父类的实例变量不能再访问子类中新添加的属性和方法【来了一个人,是男是女都不知道,所以不能访问子类特有的属性和方法;如果下面p2要访问子类的属性和方法,需要把父类的实例变量p2强制转换为子类类型】
* 2. 方法的调用是在运行时确定的,所以调用的是 Man 类的 getInfo() 方法【在多态的情况下,调用了父类的方法,这个方法已经被子类重写,运行的时候,实际上调用的是子类已经重写的那个方法,对象是子类的,所以调子类方法】。―― 动态绑定(虚拟方法调用)
* 3. 在存在父子关系(多态)的情况下, 可以把父类的引用类型强制转换为子类的引用类型. 若实际上不能进行转换则
* 系统会抛出 java.lang.ClassCastException 类型转换异常.
* 4. 如何避免出现 java.lang.ClassCastException 异常呢? 在转换之前可以先判断一下对象实际上是否为指定的子类类型.
* 使用 instanceof 运算符. 注意, 使用 instanceof 运算符, 必须要求前面的引用指向的变量和后边的类之间存在父子关系
*/
//需要一个人, 但来的是一个男人! OK. 因为男人一定是一个人.
Person p2 = new Man();
System.out.println(((Man) p2).school); // 如果p2要访问子类的属性和方法(子类有父类没有的),需要把父类的实例变量p2强制转换为子类类型
((Man) p2).work();
System.out.println(p2.getInfo()); // Man's getInfo;按住ctrl点getInfo,跳转到Person类的getInfo,方法的调用是在运行时确定的,最终调用的是Man重写的的getInfo―― 动态绑定(虚拟方法法调用) //需要一个人, 但来的是一个女人! OK. 因为女人一定是一个人
Person p3 = new Woman(); //在多态情况下, 可以进行强制的类型转换
Man m2 = (Man) p2;
// Man m4 = (Man)p3; // 会抛出 java.lang.ClassCastException 异常 System.out.println(p3 instanceof Man); // false
System.out.println(p3 instanceof Woman); // true // System.out.println(m2 instanceof Woman); // Man和Woman无父子关系
System.out.println(m2 instanceof Man); // true
System.out.println(m2 instanceof Person); // true //需要一个男人, 但来的是个人! NO. 因为人不一定是男人.
//Man m2 = new Person(); //需要个男人, 但来的是一个女人。 NO!
//Man m3 = new Woamn(); }
}
针对上面第一条,如果下面p2要访问子类的属性和方法,需要把父类的实例变量p2强制转换为子类类型
Person p2 = new Man();
System.out.println(((Man) p2).school);
((Man) p2).work();
Woman w2 = (Woman)p2; // 强制转换成女人,编译的时候可以过,因为p2是人,运行的时候不能过,因为运行时发现p2是男人
对象类型转换 (Casting )
基本数据类型的Casting
小的数据类型可以自动转换成大的数据类型
如long g=20; double d=12.0f
可以把大的数据类型强制转换(casting)成小的数据类型
如 floate f=(float)12.0 int a=(int)1200L
对Java对象的强制类型转换称为造型
从子类到父类的类型转换可以自动进行
从父类到子类的类型转换必须通过造型(强制类型转换)实现
无继承关系的引用类型间的转换是非法的,编译报错
在造型前可以使用instanceof操作符测试一个对象的类型
从小到大(小东西放到大容器中),自动转
从大到小(大东西放到小容器中),强制转
示例
package com.uncleyong; public class Person {
protected String name="person";
protected int age=50;
public String getInfo() {
return "Name: "+ name + "\n" +"age: "+ age;
}
}
class Student extends Person {
protected String school="pku";
public String getInfo() {
return "Name: "+ name + "\nage: "+ age
+ "\nschool: "+ school;
} }
class Graduate extends Student{
public String major="IT";
public String getInfo()
{
return "Name: "+ name + "\nage: "+ age
+ "\nschool: "+ school+"\nmajor:"+major;
}
}
package com.uncleyong; public class TestInstance { /*
在类中定义方法method1(Person e);
在method1中:
(1)根据e的类型调用相应类的getInfo()方法。
(2)根据e的类型执行:
如果e为Person类的对象,输出:“a person”;
如果e为Student类的对象,输出
“a student”
“a person ”
如果e为Graduate类的对象,输出:
“a graduated student”
“a student”
“a person”
*/ public void method1(Person e){ // 多态的体现,Person类型的形参可以接收实际Person子类对象
String info = e.getInfo(); // 动态绑定
System.out.println(info); if(e instanceof Graduate){
System.out.println("a graduated student");
}
if(e instanceof Student){
System.out.println("a student");
}
if(e instanceof Person){
System.out.print("a person");
} System.out.println("\n"); } public static void main(String[] args) { TestInstance ti = new TestInstance(); Person p1 = new Person();
ti.method1(p1); Person p2 = new Student();
ti.method1(p2); Person p3 = new Graduate();
ti.method1(p3); } }
Object 类及其主要方法
Object类
Object类是所有Java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
public class Person {
...
}
等价于:
public class Person extends Object {
...
}
例:
method(Object obj){…} // 可以接收任何类作为其参数
Object o=new Person;
method(o);
==操作符与equals方法
==操作符
引用类型比较引用(是否指向同一个对象,即:是否指向同一块內存空間,要求 == 两边的类型必须一致或存在着父子关系, 否则编译出错;
Person p1=new Person();
Person p2=new Person();
if (p1==p2){…}
基本类型比较值:
int a=5; if(a==6){…}
用"=="进行比较时,符号两边的数据类型必须一致(可自动转换的基本数据类型除外),否则编译出错;
equals()方法
equals()方法是Object类的方法,由于所有类都继承Object类,也就继承了equals()方法。
equals()只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象(可以比较任意两个对象)。格式:obj1.equals(obj2)
可以在类中重写 equals 方法, 以达到定制比较两个对象内容是否相等的目的
特例:当用equals()方法进行比较时,对类File、String、Date及封装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象;
原因:在这些类中,已经重写了equals()方法,可以通过 equals 方法來判定其內容是否相同
比较两个字符串的內容是否相同, 一定要使用 equals() 方法, 而不能使用 ==
toString 方法
1. Object 类定义的方法, 所以任何对象都可以来调用 toString() 方法
2. 默认情况下, toString() 方法 全类名@hash码
3. 可以根据需要重写 toString() 方法, 通常用于测试. 个别时候用于显示,增加可读性.
4. JDK 中的很多类都重写了 toString() 方法
toString()方法在Object类中定义,其返回值是String类型,返回值:类名和它的引用地址。
在进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date();
System.out.println(“now=”+now); 相当于 System.out.println(“now=”+now.toString()); // now=Date@122345
可以根据需要在用户自定义类型中重写toString()方法,如String 类重写了toString()方法,返回字符串的值。
s1=“hello”;
System.out.println(s1); // 相当于System.out.println(s1.toString());【打印对象,会自动调对象的toString方法】
基本类型数据转换为String类型时,调用了对应封装类的 toString()方法,int a=10; System.out.println(“a=”+a);
示例:
父类
package com.uncleyong; public class GeometricObject {
protected String color;
protected double weight;
}
子类
package com.uncleyong; public class Circle1 extends GeometricObject{
private double radius; public double getRadius() {
return radius;
} public void setRadius(double radius) {
this.radius = radius;
} public Circle1() {
this.radius = 1;
this.weight = 1;
this.color = "white";
} public Circle1(double radius) {
this.radius = radius;
this.weight = 1;
this.color = "white";
} public Circle1(double radius, double weight, String color) {
this.radius = radius;
this.weight = weight;
this.color = color;
} public double findArea(){
return Math.PI * this.radius * this.radius;
} @Override
public boolean equals(Object obj) {
if(this == obj){
return true;
} if(obj == null){
return false;
} if(!(obj instanceof Circle1)){
return false;
} Circle1 c = (Circle1) obj; return c.getRadius() == this.radius;
} @Override
public String toString() {
return "" + this.radius; // 写为return this.radius;不行,因为radius是double
}
}
测试类
package com.uncleyong; public class TestCircle1 { /**
* 写一个测试类,创建两个Circle对象,判断其颜色是否相等;
* 利用equals方法判断其半径是否相等;
* 利用toString()方法输出其半径。
*/
public static void main(String[] args) { Circle1 c1 = new Circle1(1, 2, "Black");
Circle1 c2 = new Circle1(2, 3, "Black");
Circle1 c3 = new Circle1(2, 2, "Black");
Circle1 c4 = new Circle1(2, 3, "Red"); // 比颜色
System.out.println(c1.color.equals(c2.color)); // true
// 比半径
System.out.println(c1.equals(c2)); // false // 比颜色
System.out.println(c3.color.equals(c4.color)); // false
// 比半径
System.out.println(c3.equals(c4)); // true System.out.println(c1); // 1.0 打印对象,会自动调对象的toString方法 }
}
封装类
针对八种基本定义相应的引用类型—封装类
int i = 10;
Integer j = 10; // Integer是封装类,基本数据类型10赋给j,自动装箱
自动装箱
Integer a = 128;
反编译生成的class文件:
Integer a = Integer.valueOf(128);
这就是基本数据类型的自动装箱,128是基本数据类型,然后被解析成Integer类。
注意:自动装箱规范要求 byte<= 127、char<=127、-128<=short <=127、-128<=int <=127都被包装到固定的对象中(缓存)。
自动拆箱
将 Integer 类表示的数据赋值给基本数据类型int,就执行了自动拆箱。
Integer a = new Integer(128);
int m = a;
反编译生成的class文件:
Integer a = new Integer(128);
int m = a.intValue();
自动装箱就是:Integer a = Integer.valueOf(int i);
自动拆箱就是:
Integer a = new Integer(128);
int m = a.intValue();
参考:https://www.cnblogs.com/uncleyong/p/9804074.html
练习题(参考答案已放在Q群文件中)
1、下面代码输出结果是?
父类
import java.util.Date; public class Person {
private String name;
private int age;
private Date birthDate; public Person(String name, int age, Date d) {
this.name = name;
this.age = age;
this.birthDate = d;
}
public Person(String name, int age) {
this(name, age, null); // 调用同一个类中的重载构造方法,三个参数的
}
public Person(String name, Date d) {
this(name, 30, d); // 调用同一个类中的重载构造方法,三个参数的
}
public Person(String name) {
this(name, 30); // 调用同一个类中的重载构造方法,两个参数的
}
public Person() {
System.out.println("父类无参构造方法");
}
}
子类
public class Student extends Person {
private String school;
public Student(String name, int age, String school) {
super(name, age);
this.school = school;
}
public Student(String name, String school) {
super(name);
this.school = school;
}
public Student(String school) {
this.school = school;
} public static void main(String[] args) {
Student student = new Student("清华大学");
System.out.println(student.school);
}
}
2、定义MyDate类,在MyDate类中覆盖equals方法,使其判断当两个MyDate类型对象的年月日都相同是,结果为ture,否则为false。
TestEquals.java
Java【第七篇】面向对象之类设计的更多相关文章
- java 第七章 面向对象高级特性
一.类的继承 (一)继承的含义 1.在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化). 2.被继承的类称为父类(超类,基类),新的类称为子类(派生类). ...
- java 28 - 1 设计模式 之 面向对象思想设计原则和模版设计模式概述
在之前的java 23 中,了解过设计模式的单例模式和工厂模式.在这里,介绍下设计模式 面向对象思想设计原则 在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设 ...
- 第七篇 :微信公众平台开发实战Java版之如何获取微信用户基本信息
在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的.对于不同公众号,同一用户的openid不同). 公众号可通过本接口来根据O ...
- Python开发【第七篇】:面向对象 和 python面向对象进阶篇(下)
Python开发[第七篇]:面向对象 详见:<Python之路[第五篇]:面向对象及相关> python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)> ...
- Java面向对象课程设计——购物车
Java面向对象课程设计——购物车 小组成员:余景胜.刘格铭.陈国雄.达瓦次仁 一.前期调查 流程 客人(Buyer)先在商城(Mall)中浏览商品(Commidity),将浏览的商品加入购物车(Sh ...
- PHP 进阶篇:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 (麦子学员 第三阶段)
以下是进阶篇的内容:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 ================================== ...
- java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
- Python开发【第七篇】:面向对象
Python之路[第五篇]:面向对象及相关 面向对象基础 基础内容介绍详见一下两篇博文: 面向对象初级篇 面向对象进阶篇 其他相关 一.isinstance(obj, cls) 检查是否obj是否 ...
- 【Python之路】第七篇--Python基础之面向对象及相关
面向对象基础 基础内容介绍详见一下两篇博文: 面向对象初级篇 面向对象进阶篇 其他相关 一.isinstance(obj, cls) 检查obj是否是类 cls 的对象 class Foo(objec ...
- GOF 的23种JAVA常用设计模式总结 03 面向对象七大设计原则
在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据 7 条原则来开发程序,从而提高软件开发效率.节约软件开发成本和维护成本. 各位代码界的大佬们总结出的七 ...
随机推荐
- 从零学习Fluter(三):Flutter的路由跳转以及state的生命周期
今天继续研究Flutter,我是在flutter1.0发布后,才玩flutter的,发现在此之前,许多人已经先发制人,玩起了flutter,不知不觉中,我已经被别人摔在了起跑线上,玩过flutter后 ...
- 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署
目录 目录 1.基本概念 1.1.什么是智能合约? 1.2.什么是Solidity? 1.2.1.Solidity的语言特性 1.3.什么是 Browser-solidity? 2.Browser-s ...
- python 爬取全本免费小说网的小说
这几天朋友说想看电子书,但是只能在网上看,不能下载到本地后看,问我有啥办法?我找了好几个小说网址看了下,你只能直接在网上看,要下载txt要冲钱买会员,而且还不能在浏览器上直接复制粘贴.之后我就想到py ...
- Powershell-获取命令和帮助
Get-Help 获取命令的帮助文档 Update -Help 更新帮助文档 Save-Help 保存文档 Get-Help Get-VM 加上-Full参数获取详细说明 [-name] <st ...
- bsp makefile2
1. grep "bsp_dir" -r ./ -s --exclude-dir "*.git" 用这个加快目录定位-- 2.编译所有子目录 for dir ...
- 浅析String类
这是对于String类的一些总结,我将会从几个方面并且结合着字符串池等相关知识进行总结 进程如下: 1.对于String类基本知识的一些总结 2.简要介绍字符串池 3.分 ...
- ElasticSearch(九):elasticsearch-head插件安装
安装node 安装elasticsearch-head需要node.js的支持. 下载最新的node.js,下载地址:https://nodejs.org/en/download/ 将下载后的安装包放 ...
- Django-CRM项目学习(五)-stark的action以及多级筛选功能
1.stark的组件之action(自定制函数多选功能效果) 1.1 admin效果 1.2 多选效果前端和后端进行的操作 1.2.1 前端发过来的参数是?号后各个参数用&来拼接 1.2.2 ...
- Java 前后端List传值
js代码 function click(){ var arrays = new Array(); for (var i = 0; i < arr.length; i++) { arrays.pu ...
- 正益移动推出新产品正益工作 实现PaaS+SaaS新组合
近期,正益移动不仅将其AppCan 移动平台云化,还通过发布全新 SaaS 产品 -- 正益工作,这款集合了企业信息聚合.应用聚合.社交聚合为一体的企业移动综合门户,与 AppCan 平台一起实现了P ...