目录
OOP特征二:继承性
继承的概念:
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个无需再定义这些属性和行为,只要继承那个类的行为。
子类与父类:此处的多个类称为子类 (派生类 ),单独的这个类称为父类 (基类或超类 )。可以理解为 :”子类 is a 父类“
继承的作用:
-
继承的出现减少了代码冗余,提高 了代码的复用性。
-
继承的出现,更有利于功能扩展。
-
继承的出现让类与之间产生了关系 ,提供了多态的前提 。
类继承语法规则 :
class A extends B{
//A:子类、派生类、subclass
//B:父类、超类、基类、superclass
}
继承的体现:
-
一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。但是因为封装性的影响,使得子类不能直接调用父类的结构而已。例如Student类不能直接调用Person类的私有属性或方法,但是可以通过get()和set()方法进行调用。
-
子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。子类和父类的关系,不同于子集和集合的关系。
extends:延展、扩展
java中关于继承的规定:
-
一个类可以被多个子类继承。
-
Java中类的单继承性:一个类只能有一个父类
-
子父类是相对的概念。
-
子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类。比如说Boy类继承Student类,Student类继承Person类,Boy类间接继承Person类。
-
子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
Object类:
-
如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
-
所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
-
意味着,所有的java类具有java.lang.Object类声明的功能。
练习1:
(1)定义一个ManKind类,包括成员变量int sex和int salary;方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0);方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
(2)定义类Kids继承ManKind,并包括成员变量int yearsOld;方法printAge()打印yearsOld的值。
(3)定义类KidsTest,在类的main方法中实例化Kids的对someKid,用该对象访问其父类的成员变量及方法。
代码实现:
ManKind类:
public class ManKind {
private int sex;
private int salary;
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman(int sex) {
if(sex==1) {
System.out.println("man");
}
else if (sex==0) {
System.out.println("woman");
}
}
public void employeed() {
if(salary==0) {
System.out.println("no job");
}
else if (salary!=0) {
System.out.println("job");
}
//或
// String jobInfo = (salary==0)? "no job" : "job";
// System.out.println(jobInfo);
}
// public ManKind{
//
// }
}
Kids类:
public class Kids extends ManKind{
private int yearsOld;
public Kids() {
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge() {
System.out.println("I am "+yearsOld);
}
}
KidsTest类:
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();//调用它自己的方法,打印一下自己年龄属性,创建对象的时候初始化的yearsOld属性值是12
someKid.setSalary(0);//调用父类ManKind类的私有属性salary的set()方法,
// 传入参数0,给私有属性salary赋值=0
someKid.setSex(1);//调用父类ManKind类的私有属性sex的set()方法,
// 传入参数1,给私有属性sex赋值=0
someKid.employeed();//调用父类ManKind类的方法employeed()
someKid.manOrWoman(0);//调用父类ManKind类的方法manOrWoman()
//调用方法的时候传入参数0,
}
}
练习2:
根据下图实现类 。在 CylinderTest 类中创建Cylinder 类的对象,设置圆柱的底面半径和高,并输出圆体积。
代码实现:
Circle类:
public class Circle {
private double radius;//半径
public Circle(){
radius = 1.0;
}
public Circle(double radius){
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
//返回圆的面积
public double findArea(){
return Math.PI * radius * radius;
}
}
Cylinder 类:
public class Cylinder extends Circle{
private double length;//高
public Cylinder(){
length = 1.0;
}
public Cylinder(double length) {
this.length=length;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
//返回圆柱的体积
public double findVolume(){
// return Math.PI * getRadius() * getRadius() * getLength();
return super.findArea() * getLength();
// return findArea()* getLength();
//因为Cylinder类中也要定义一个计算表面积的方法findArea(),
//所以一时分不清楚是哪个类的findArea()方法,这个时候可以通过super关键字来表示
//是父类Circle类的findArea()方法
}
@Override
public double findArea() {//返回圆柱的表面积
return Math.PI * getRadius() * getRadius() * 2 + 2 * Math.PI * getRadius() * getLength();
}
}
CylinderTest 类:
public class CylinderTest {
public static void main(String[] args) {
Cylinder cy = new Cylinder();
cy.setRadius(2.1);
cy.setLength(3.4);
double volume = cy.findVolume();
System.out.println("圆柱的体积为:" + volume);
//没有重写findArea()时:
// double area = cy.findArea();
// System.out.println("底面圆的面积:" + area);
//重写findArea()以后:
double area = cy.findArea();
System.out.println("圆柱的表面积:" + area);
System.out.println("******************");
Cylinder cy1 = new Cylinder();
double volume1 = cy1.findVolume();
System.out.println("圆柱的体积为:" + volume1);
}
}
方法的重写(override)
定义:在子类中可以根据需要对从父继承来的方法进行改造,也称为方法的重置、覆盖 。 在程序执行时,子类的方法将覆盖父类的方法。
注:在子类中对父类进行继承中,属性没有重写和覆盖一说,就算在子类和父类中分别声明同一数据类型和同一变量名,那么在内存中就有两个属性。
要求:
-
子类重写的方法 必须 和父类被重写的方法具有相同的方法名称、 参数列表
-
子类重写的方法返回值类型不能大于父类被重写的方法返回值类型
-
子类重写的方法使用访问权限不能小于父类被重写的方法的访问权限
-
子类不能重写父中声明为 private 权限的方法
-
子类方法 抛出的异常类型不能大于父类被重写方法的异常类型
//方法的声明:
权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
// 方法体
}
-
返回值类型:
-
父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
-
父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
-
父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
-
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。
注意:
子类与父类中同名同参数的方法必须同时声明为非static的(即为重写 ),或者同时声明为 static 的(不是重写 )。因为 static 方法是属于类的,子类无法覆盖父类的方法。
四种访问权限修饰符
-
Java规定的4种权限(从小到大排列):private、缺省、protected 、public
-
4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
-
4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
-
修饰类的话,只能使用:缺省、public
总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
关键字:super
-
在Java 类中使用 super 来调用父类中的指定操作:
-
super 可用于访问父类中定义的属性
-
super 可用于调父类中定义的成员方法
-
super 可用于在子类构造器中调用父类的构造器
注意:
-
尤其 当子父类出现同名成员时 ,可以用super表明调用的是父类中成员
-
super的追溯不仅限于直接父类
-
super和this 的用法相像的,this是因为属性和形参重名,super是因为父类的方法和子类中重写方法重名,this代表本类对象的引用 ,super 代表父类的内存空间的标识。
super的使用:调用属性和方法
-
我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
-
特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
-
特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
super调用构造器
-
我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
public Student(String name,int age,String major){
// this.name = name;
// this.age = age;//name,age是父类中声明的构造器里的属性
super(name,age);//必须在子类构造器的首行
this.major = major;
}
-
"super(形参列表)"的使用,必须声明在子类构造器的首行!
-
我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
-
在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列表)",则默认调用的是父类中空参的构造器:super()
-
在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器
子类对象实例化过程
-
从结果上来看:(继承性)
-
子类继承父类以后,就获取了父类中声明的属性或方法。
-
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
2.从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,...
直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
注:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
OOP特征三:多态性
多态性的概念:
多态性,是面向对象中最重要的概念 ,在Java 中的体现:对象 的多态性:父类的引用指向子类的对象(子类的对象赋给父类的引用)。
多态性的使用:(虚拟方法调用)
Java引用变量有两个类型: 编译时类型 和运行时类型 。
Person p2 = new Man();
编译时类型由声明 该变量时使用的类型决定 (声明为左边Person类类型),运行时类型由实际赋给该变量的对象决定(实际赋给该变量的对象类型是右边Man类类型) 。
简称:编译 时,看左边;运行时 ,看右边 。若编译时类型和运行不一致 ,就出现了对象的多态性 (Polymorphism)
多态情况下 :
“看左边 ”:看的是父类引用 (父类中不具备子特有的方法 )“看右边 ”:看的是子类对象 (实际运行的是子类重写父方法 )
虚拟方法调用 (Virtual Method Invocation):
-
正常的方法调用
Person e = new Person();
e.getlnfo();
Student e = new Student();
e.getInfo();
-
虚拟方法调用(多态情况下)
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
Person e = new Student();//Person类是Student类的父类
e.getlnfo();//调用Student类的getlnfo()方法
-
编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getlnfo()方法。——动态绑定
多态性的使用前提:
-
左边声明的类和右边实际赋值的类具有继承关系
-
子类和父类中必须有重写的方法
对象的多态性的适用范围:
-
只适用于方法,不适用于属性(编译和运行都看左边)
多态性的使用举例(多态性的必要性):
import java.sql.Connection;
//多态性的使用举例一:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.func(new Dog());//Animal animal = new Dog();
test.func(new Cat());//Animal animal = new Cat();
}
public void func(Animal animal){//Animal animal = new Animal子类();
animal.eat();
animal.shout();
if(animal instanceof Dog){
Dog d = (Dog)animal;
d.watchDoor();
}
}
//没有多态性的话就只能一个一个定义重载的方法
// public void func(Dog dog){
// dog.eat();
// dog.shout();
// }
// public void func(Cat cat){
// cat.eat();
// cat.shout();
// }
}
class Animal{
public void eat(){
System.out.println("动物:进食");
}
public void shout(){
System.out.println("动物:叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void shout(){
System.out.println("汪!汪!汪!");
}
public void watchDoor(){
System.out.println("看门");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void shout(){
System.out.println("喵!喵!喵!");
}
}
//举例二:
class Order{
public void method(Object obj){
}
}
//举例三:
class Driver{
public void doData(Connection conn){//操作数据库处理数据,调用该方法的时候传的参数大多
//是Connection的子类的对象
//Connection conn = new MySQlConnection();
//Connection conn = new OracleConnection();
//规范的步骤去操作数据
// conn.method1();
// conn.method2();
// conn.method3();
//上述三个方法只需要在父类Connection中定义的,真正操作的时候是在它的子类
//MySQlConnection()/OracleConnection()操作
}
}
instanceof关键字的引入
向下转型的的使用:
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。 如何才能调用子类特有的属性和方法?
向下转型:使用强制类型转换符。Person p1 = new Person();
Person p1 = new Person();
Man man = new Man();
Person p2 = new Man();
Man m1 = (Man)p2;//强制类型转换
m1.earnMoney();
m1.isSmoking = true;
//使用强转时,可能出现ClassCastException的异常。
//Woman w1 = (Woman)p2;
//w1.goShopping();
//为了避免这个问题,这个时候就需要iinstanceof关键字
instanceof关键字的使用
-
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
-
使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
-
如果,类B是类A的父类。
a instanceof A返回true,则 a instanceof B也返回true.
向下转型的常见问题:
//问题一:编译时通过,运行时不通过
//举例一:
// Person p3 = new Woman();
// Man m3 = (Man)p3;
//举例二:
// Person p4 = new Person();
// Man m4 = (Man)p4;
//问题二:编译通过,运行时也通过
// Object obj = new Woman();
// Person p = (Person)obj;
//问题三:编译不通过
// Man m5 = new Woman();
// String str = new Date();
// Object o = new Date();
// String str1 = (String)o;
多态性练习:调用属性和方法
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;//多态性
//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10,多态性不适用于属性
b.display();//20,多态性适用于方法,实际执行的是子类的重写方法,数据类型属于右边,这是虚拟方法调用
}
}
多态性练习:基本操作
要求:
在method中:
(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 class InstanceTest {
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
}
public void method(Person e){
//虚拟方法调用
String info = e.getInfo();
System.out.println(info);
//方式一
// if(e instanceof Graduate){
// System.out.println("a graduated student");
// System.out.println("a student");
// System.out.println("a person");
// }else if(e instanceof Student){
// System.out.println("a student");
// System.out.println("a person");
// }else{
// System.out.println("a person");
// }
//方式二
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.println("a person");
}
}
}
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;
}
}
多态性练习:几何图形
Circle类:
public class Circle extends GeometricObject {
private double radius;
public Circle(double radius,String color, double weight) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){
return 3.14 * radius * radius;
}
}
GeometricObject类:
public class GeometricObject {//几何图形
protected String color;
protected double weight;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public double findArea(){
return 0.0;
}
}
MyRectangle类:
public class MyRectangle extends GeometricObject {
private double width;
private double height;
public MyRectangle(double width,double height,String color, double weight) {
super(color, weight);
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public double findArea() {
return width * height;
}
}
测试类:
/*
* 定义一个测试类GeometricTest,
* 编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),
* 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
*/
public class GeometricTest {
public static void main(String[] args) {
GeometricTest test = new GeometricTest();
Circle c1 = new Circle(3.3, "white", 1.0);
test.displayGeometricObject(c1);
Circle c2 = new Circle(3.3, "white", 1.0);
test.displayGeometricObject(c2);
boolean isEquals = test.equalsArea(c1, c2);
System.out.println("c1 和 c2的面积是否相等:" + isEquals);
MyRectangle rect = new MyRectangle(2.1, 3.4, "red", 2.0);
test.displayGeometricObject(rect);
}
public void displayGeometricObject(GeometricObject o){//GeometricObject o = new Circle(...)
System.out.println("面积为:" + o.findArea());
}
//测试两个对象的面积是否相等
public boolean equalsArea(GeometricObject o1,GeometricObject o2){
return o1.findArea() == o2.findArea();
}
}
Object类的使用
-
Object类是所有Java类的根父类
-
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
public class Person {
...
}
等价于:
public class Person extends Object {
...
}
-
Object类中的功能(属性、方法)就具有通用性。(可以上jdk文档查看)
-
属性:无
-
方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()/wait() /notify()/notifyAll()
-
构造器:Object类只声明了一个空参的构造器
-
-
例:
method(Object obj)X{...]//可以接收任何类作为其参数
Person o=new Pers on();
method(o);
运算符 == 与 equals 方法
-
运算符 == 的使用
-
可以使用在基本数据类型变量和引用数据类型变量中
-
如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同).基本类型 比较值 :只要两个变量的值相等 ,即为true 。
//基本数据类型 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);//这个会报错,因为基本数据类型在计算的时候不和boolean类型玩 char c = 10; System.out.println(i == c);//true char c1 = 'A';//对应的ASIIC码就是65 char c2 = 65; System.out.println(c1 == c2);//true
-
如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体。引用 类型比较引用(是否指向同一个对象 ):只有指向同一个对象时 , == 才返回 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
-
补充: == 符号使用时,必须保证符号左右两边的变量类型一致。
-
-
equals()方法的使用:
-
是一个方法,而非运算符
-
只能适用于引用数据类型
-
Object类中equals()的定义:
public boolean equals(Object obj) { return (this == obj); }
说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
-
像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
-
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写.
-
重写的原则:比较两个对象的实体内容是否相同.
-
重写equals()方法的原则
-
对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
-
自反性: x.equals(x)必须返回是“true”。
-
传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
-
一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
-
任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
-
开发的时候我们可以自动生成equals()方法:
—Source—Generate hashCode() and equals.
-
== 和equals的区别
-
== 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
-
equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
-
具体要看自定义类里有没有重写Object的equals方法来判断。
-
通常情况下,重写equals方法,会比较类中的相应属性是否都相等。
equals方法的练习:
-
编写Order类,有int型的orderld,String型的orderName,相应的getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创健的两个对象是否相等。
2.请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。 public boolean equals(Object o)
toString()方法的使用
toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。
-
在进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date();
System.out.printIn("now="+now);相当于System.out.printIn(now="+now.toString());
-
可以根据需要在用户自定义类型中重写toString()方法如String类重写了toString()方法,返回字符串的值。
s1="hello";
System.out.printIn(s1);/l相当于System.out.printIn(s1.toString());
-
基本类型数据转换为String类型时,调用了对应包装类的toString()方法
int a=10; System.out.println(a=+a);
Object类中toString()的使用:
-
当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
-
Object类中toString()的定义:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}
-
像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息
-
自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
Object类的练习
GeometricObject类
public class GeometricObject {
protected String color;
protected double weight;
public GeometricObject() {
super();
this.color = "white";
this.weight = 1.0;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
Class类:
public class Circle extends GeometricObject {
private double radius;
public Circle() {
super();
radius = 1.0;
// color = "white";
// weight = 1.0;
}
public Circle(double radius) {
super();
this.radius = radius;
}
public Circle(double radius,String color,double weight) {
super(color,weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
//求圆的面积
public double findArea(){
return 3.14 * radius * radius;
}
//比较两个圆的半径是否相等,如相等,返回true。
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof Circle){
Circle c = (Circle)obj;
return this.radius == c.radius;
}
return false;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
CircleTest类:
public class CircleTest {
public static void main(String[] args) {
Circle circle1 = new Circle(2.3);
Circle circle2 = new Circle(3.3, new String("white"), 2.0);
System.out.println("颜色是否相等:" + circle1.getColor().equals(circle2.getColor()));
System.out.println("半径是否相等:" + circle1.equals(circle2));
System.out.println(circle1);
System.out.println(circle2.toString());
}
}
Java中的JUnit单元测试
-
步骤:
-
选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
-
创建Java类,进行单元测试。此时的Java类要求:① 此类是public的 ②此类提供公共的无参的构造器
-
此类中声明单元测试方法。此时的单元测试方法:方法的权限是public,没有返回值,没有形参
-
此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
-
声明好单元测试方法以后,就可以在方法体内测试相关的代码。
-
写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test
-
说明:
-
如果执行结果没有任何异常:绿条
-
如果执行结果出现异常:红条
import java.util.Date;
import org.junit.Test;
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());
}
}
包装类(Wrapper)的使用
java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征.
基本数据类型、包装类、String三者之间的相互转换
-
基本数据类型 --->包装类
//基本数据类型 --->包装类:调用包装类的构造器
//有一些方法的形参,如果是类类型,就必须把基本数据类型转化为类类型
@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);//f表示是float类型
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
//布尔类型以字符串的形式导入类,忽略大小写,只要字符串内容是true就是true,其他就是false
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);//true
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);//打印order对象的isFemale类属性,初始值为null
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
-
包装类--->基本数据类型
//包装类--->基本数据类型:调用包装类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);
}
-
自动装箱和自动拆箱
/*
* 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;//自动拆箱
}
-
基本数据类型、包装类--->String类型
//基本数据类型、包装类--->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"
}
-
String类型 --->基本数据类型、包装类
//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";//false
// String str2 = "true";//true
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
包装类练习
//下列两个方法输出结果相同吗,各是什么?
@Test
public void test1() {
//三目运算符编译冒号前后类型必须统一
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);// 1.0
}
@Test
public void test2() {
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);// 1
}
//不相同第一个方法输出1.0
//第二个方法输出1
测试:
public class InterviewTest {
@Test
public void test3() {
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对象
Integer y = 128;//相当于new了一个Integer对象
System.out.println(x == y);//false
}
}
练习3:
利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
-
提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。
-
创建Vector对象:Vector v=new Vector();
-
给向量添加元素:v.addElement(Object obj); //obj必须是对象
-
取出向量中的元素:Object obj=v.elementAt(0);
-
注意第一个元素的下标是0,返回值是Object类型的。
-
-
计算向量的长度:v.size();
-
若与最高分相差10分内:A等;20分内:B等;
30分内:C等;其它:D等
ScoreTest类:
import java.util.Scanner;
import java.util.Vector;//向量类java.util.Vector可以根据需要动态伸缩。
public class ScoreTest {
public static void main(String[] args) {
//1.实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
//2.创建Vector对象:Vector v=new Vector();相当于原来的数组
Vector v = new Vector();
//3.通过for(;;)或while(true)方式,给Vector中添加数组
int maxScore = 0;
for(;;){
System.out.println("请输入学生成绩(以负数代表输入结束)");
int score = scan.nextInt();
//3.2 当输入是负数时,跳出循环
if(score < 0){
break;
}
if(score > 100){
System.out.println("输入的数据非法,请重新输入");
continue;
}
//3.1 添加操作::v.addElement(Object obj)
//jdk5.0之前:
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多态
//jdk5.0之后:
v.addElement(score);//自动装箱
//4.获取学生成绩的最大值
if(maxScore < score){
maxScore = score;
}
}
//5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级。
char level;
for(int i = 0;i < v.size();i++){
Object obj = v.elementAt(i);
//jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
//jdk 5.0之后:
int score = (int)obj;
if(maxScore - score <= 10){
level = 'A';
}else if(maxScore - score <= 20){
level = 'B';
}else if(maxScore - score <= 30){
level = 'C';
}else{
level = 'D';
}
System.out.println("student-" + i + " score is " + score + ",level is " + level);
}
}
}