首页 > 编程语言 > 详细

8java继承、方法重写、权限修饰符、super关键字、对象实例化过程、多态、Object类、包装类

时间:2020-03-22 11:18:20      阅读:80      评论:0      收藏:0      [点我收藏+]

继承

如果让你创建学生类你可能一下就能创建完,但是如果让你创建学生类,工人类,教师类,农民类,而且这些类的属性都有相同的属性和方法:姓名,年龄,性别,打印个人信息的方法。按照前面说的把代码写出来,如果直接这样去硬写,是不是代码的重复就很多。

Java提供了一个继承机制,可以解决这个问题。

首先创建一个人类,把要创建的类的相同属性放到人类里面,然后其他类只需要添加自己特有的属性和方法就行,其他的属性继承就行。  

技术分享图片

技术分享图片
public class Person {//人类   ——父类
    private int age;
    private String name;
    private String sex;
    //下面的get和set方法自动生成,右键source > Generate Getter and Setter
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

class Students extends Person{ //学生类继承了人类     子类继承父类    注意一个类中只能有一个public修饰的类
    private String school;//子类继承父类后,子类拥有父类的所有属性和方法,不必再次添加属性
    
    public static void main(String[] args) {
        Students s = new Students();//创建学生对象
        s.setName("张三");//调用了Person父类的方法
        System.out.println(s.getName());//这里也是调用父类的方法打印名字
    }
}
View Code

 技术分享图片

 

 技术分享图片

 

不要为了获取其他类中的某些属性/方法/功能而去继承。比如创建一个狗类,狗也有姓名,年龄,性别。但是狗类可以继承人类吗,不可以。虽然语法上不会报错,但是思想上不符合逻辑。如果狗类想继承,可以创建一个动物类,然后狗类继承动物类。

继承需要逻辑关系在里面,不要随意继承。

 

 技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 练习1.1

 技术分享图片

技术分享图片
//ManKind类
public class ManKind {
    int sex,salary;//定义属性
    
    public void manOrWorman() {//判断男/女
        if(this.sex==1) {
            System.out.println("man");
        }
        else if(this.sex==0){
            System.out.println("women");
        }
        else {
            System.out.println("请输入正确的年龄数字");
        }
    }
    
    public void employedd() {//判断是否有工作
        if(this.salary==0) {
            System.out.println("no job");
        }
        else if(this.salary!=0) {
            System.out.println("job");
        }
    }
}


//Kids类
public class Kids extends ManKind{//继承ManKind父类
    private int yearsOld;
    
    public void printAge() {
        System.out.println(this.yearsOld);
    }
    public static void main(String[] args) {
        Kids someKid = new Kids();//创建kids子类对象
        someKid.salary=1;//调用父类属性
        someKid.sex=1;
        someKid.employedd();//调用父类方法
        someKid.manOrWorman();
    }
}
View Code

技术分享图片

技术分享图片
//Circle类
public class Circle {
    private double radius;
    public Circle() {
        radius = 1;
    }
    //设置半径
    public void setRadius(double radius) {
        this.radius = radius;
    }
    //返回半径
    public double getRadius() {
        return this.radius;
    }
    //计算圆面积公式
    public double findArea() {
        return 3.14*radius*radius;
    }
}

//Cylinder类
public class Cylinder extends Circle {//圆柱继承圆
    private double length;//
    public Cylinder() {
        length = 1;
    }
    
    public void setLength(double length) {
        this.length = length;
    }
    
    public double getLength() {
        return this.length;
    }
    
    //计算圆体积:底面积*高
    public double findVolume() {
        return findArea()*getLength(); 
    }
}

//TestCylinder类
public class TestCylinder {
    public static void main(String[] args) {
        Cylinder cylinder = new Cylinder();
        cylinder.setRadius(3);//设置继承父类圆的半径
        cylinder.setLength(3);//设置圆柱的高
        System.out.println(cylinder.findVolume());//调用计算圆柱体积公式
    }
}

//注意上面的三个类我放在一起了,如果复制在同一类中,只能保留其他一个public修饰符,其他public去掉
View Code

方法的重写

技术分享图片

 

 例子:

技术分享图片
//person类
public class Person {//父类
    private int age;
    private String name;
    private int sex;
    
    public void showInfo() {
        System.out.println("父类的方法");
        System.out.println(this.age);
        System.out.println(this.name);
        System.out.println(this.sex);
    }
    
    public void setInfo(int age, String name , int sex) {
        System.out.println("父类的方法");
        this.age = age;
        this.name = name;
        this.sex = sex;
    }
}


//student类
public class Student extends Person{
    private String school;
    
    public void showInfo() {
        System.out.println("子类的方法,这里方法名一致,参数列表也是空的,返回值类型一致,算是重写了父类的方法");
        System.out.println(this.school);
    }
    
    public void showInfo(String school) {
        System.out.println("这里改变了父类的参数列表,不算是重写父类的方法但是方法名和上面一致构成了方法重载");
        System.out.println(school);
    }
    
    
    public void setInfo(String school) {
        System.out.println("子类的方法,这里改了父类的参数列表,不算方法的重写");
        System.out.println(school);
    }
    
    public static void main(String[] args) {
        Student student = new Student();
        student.showInfo();//调用了本类中的方法,因为父类的showInfo被重写了
        student.showInfo("学校");//调用了本类的重载方法
        student.setInfo(18, "猪头", 1);//这里调用的是父类的方法,虽然这个方法和本类的方法setInfo名字相同,但是参数列表不同,不算重写父类的方法
    }
}
View Code

技术分享图片

 

 注意:方法的重载和方法的重写区别,方法的重载:一个类可以有多个同名的方法。方法的重写:子类可以重写父类的方法,覆盖父类方法

练习:

技术分享图片

 重写父类的方法,只能修改方法体的内容,返回值、参数列表、方法名必须一致,而且修饰符的访问权限子类不能大于父类的,才算是重写父类的方法,这里违法了修饰符访问权限大于父类,不构成方法的重写。

注意:只要父类有private修饰,其他类就访问不了该类被private修饰的属性/方法,如果要重写父类的方法,父类不能是private修饰,这样子类就算想重写父类也做不到。

技术分享图片

技术分享图片
//Mankind类上面的1.1练习有

//Kids类
public class Kids extends ManKind{//继承ManKind父类
    private int yearsOld;
    
    public void printAge() {
        System.out.println(this.yearsOld);
    }
    
    public void employed() {
        System.out.println("Kids should study and no job");
    }
    
    public static void main(String[] args) {
        Kids someKid = new Kids();//创建kids子类对象
        someKid.salary=1;//调用父类属性
        someKid.sex=1;
        someKid.employed();//调用重写父类的方法,就是本类的方法
        someKid.manOrWorman();
    }
}
View Code

权限修饰符

技术分享图片

 

 

 技术分享图片

super关键字

 技术分享图片

 

 例子:

技术分享图片
//Person1类
public class Person1 {
    String name;//父类属性
    int age;
    public Person1() {}//父类无参构造
    public Person1(String name,int age) {//父类有参构造
        this.name = name;
        this.age = age;
    }
    public void showMsg(String name,int age) {//父类的方法
        System.out.print("姓名:"+name+" 年龄:"+age+" ");
    }
}

//Student1类
public class Student1 extends Person1 {//继承Person1父类
    private String school;
    public Student1() {}
    public Student1(String name,int age,String school) {//子类构造
        super(name,age);//调用父类的构造方法
        this.school = school;
    }
    public void showMsg() {
        super.showMsg(this.name, this.age);//调用父类的方法,使用继承的属性
        System.out.println("学校:"+this.school);
    }
    public static void main(String[] args) {
        Student1 student = new Student1("质数",19,"北大");
        student.showMsg();
    }
}
View Code

练习:

技术分享图片

技术分享图片
public class Kids extends ManKind{//继承ManKind父类
    private int yearsOld;
    
    public void printAge() {
        System.out.println(this.yearsOld);
    }
    
    public void employed() {
        super.employed();//调用父类方法
        System.out.println("but Kids should study and no job");
    }
    
    public static void main(String[] args) {
        Kids someKid = new Kids();//创建kids子类对象
        someKid.salary=1;//调用父类属性
        someKid.sex=1;
        someKid.employed();//调用重写父类的方法,就是本类的方法
        someKid.manOrWorman();
    }
}
View Code

技术分享图片

技术分享图片
//Circle父类
public class Circle {
    private double radius;
    public Circle() {
        radius = 1;
    }
    //设置半径
    public void setRadius(double radius) {
        this.radius = radius;
    }
    //返回半径
    public double getRadius() {
        return this.radius;
    }
    //计算圆面积公式
    public double findArea() {
        return 3.14*radius*radius;
    }
}

//Cylinder类
public class Cylinder extends Circle {//圆柱继承圆
    private double length;//
    public Cylinder() {
        length = 1;
    }
    
    public void setLength(double length) {
        this.length = length;
    }
    
    public double getLength() {
        return this.length;
    }
    
    //覆盖计算圆面积公式,改为计算圆柱表面积:  2*π*半径*高+π*半径²*2
    public double findArea() {
        return 2*(3.14*super.getRadius()*this.length)+(3.14*super.getRadius()*super.getRadius())*2;
    } 
    
    //计算圆体积:底面积*高,底面积=(表面积-(2*π*半径*高))/2
    public double findVolume() {
        return getLength()*((findArea()-(2*3.14*super.getRadius()*getLength()))/2); 
    }
}

//TesCylinder测试类
public class TestCylinder {
    public static void main(String[] args) {
        Cylinder cylinder = new Cylinder();
        cylinder.setRadius(3);//设置继承父类圆的半径
        cylinder.setLength(3);//设置圆柱的高
        System.out.println(cylinder.findArea());//计算圆柱表面积
        System.out.println(cylinder.findVolume());//调用计算圆柱体积公式
        
        Circle circle = new Circle();
        circle.setRadius(3);
        System.out.println(circle.findArea());//计算父类圆的面积
    }
}
View Code

 技术分享图片

技术分享图片
//TestFather类
public class TestFather {
    public int age;
    public int sex;
    public String name;

    public TestFather(int age,int sex,String name) {
        this.age = age;
        this.sex = sex;
        this.name = name;
    }
    public void show() {
        System.out.println("父类的this");
    }
    public TestFather() {
        System.out.println("子类默认调用父类的无参构造");
    }
    
}

//TestSon类
public class TestSon extends TestFather{
    private String course;
    
    public TestSon(int age,int sex,String name,String course) {
        super(age, sex, name);//当父类没有无参构造器时,要指定父类的有参构造,否则报错,因为默认访问父类无参构造
        this.course = course;
    }
    
    public TestSon() {
        //当子类构造器里面没有指定使用父类或本类构造器时   默认访问父类构造
        //如果父类不存在无参构造    这里的无参构造器又没指定父类的有参构造或本类其他构造会报错
    }
    
    public static void main(String[] args) {
        TestSon testSon = new TestSon();//这里会去访问父类的无参构造
    }
}
View Code

总结:父类只要存在无参构造,子类继承了必须要存在无参构造,父类存在有参构造,子类也必须存在有参构造,否则报错。this.属性/方法指定本类的属性/方法时,如果本类不存在,则寻找父类的(构造方法除外),super直接指定父类的属性/方法,多层继承也可访问到。

 技术分享图片

简单类对象实例化过程

技术分享图片

技术分享图片
public class TestSon{
    private int age;//3属性默认初始化 ,基本类型默认初始为0,引用类型为null,默认初始完,到4构造方法进栈
    static{
        System.out.println("最先执行加载TestSon.class文件,再到静态,静态只执行1次");
        System.out.println("1静态代码块");
    }

    private int sex = 1;//5对属性进行显示初始化
    public TestSon() {//4构造方法进栈,进栈之后不会先进入构造方法,而是5对属性进行显示初始化
        System.out.println("6然后才进入无参构造");
    }//这里构造方法弹栈,弹栈之后就进行7地址赋值给变量
    
    public static void main(String[] args) {
        System.out.println("2进入main");
        TestSon p = new TestSon();//先进栈为p分配空间,再到堆为new TestSon()分配空间,并在对象空间中,对对象的(3)属性进行默认初始化
        System.out.println("7把new TestSon()对象的堆地址赋值给p变量");
    }
}
View Code

总结:

  1. 加载TestSon.class文件进内存
  2. 在栈内存为p开辟空间
  3. 在堆内存为TestSon对象开辟空间
  4. 对TestSon对象的成员变量进行默认初始化
  5. 构造方法进栈
  6. 对TestSon对象的成员变量进行显示初始化
  7. 进入构造方法
  8. 构造方法弹栈
  9. TestSon对象初始化完毕,把对象地址赋值给p变量

子类对象实例化过程

 技术分享图片

技术分享图片
//TestFather类
public class TestFather {

    static{
        System.out.println("最先执行加载父类和子类的class文件,再到静态,静态只执行1次");
        System.out.println("1先执行父类静态代码块");
    }
    private int age;//3先父类默认初始化
    private int sex = 1;//6父类显示初始化属性

    public TestFather() {//5父类的构造进栈,然后不会进入构造方法内,而是6父类显示初始化属性
        System.out.println("父类显示初始化属性完后。--子类默认先调用父类的无参构造");
    }//父类构造方法弹栈,到了7子类显示初始化属性
    
}


//TestSon类
public class TestSon extends TestFather{
    private int age;//3属性默认初始化 ,基本类型默认初始为0,引用类型为null,默认初始完,到4构造方法进栈
    static{
        System.out.println("2子类静态代码块");
    }

    private int sex = 1;//7子类显示初始化属性,显示初始化完后,进入8构造方法
    public TestSon() {//4子类构造方法先进栈,然后5父类的构造进栈
        System.out.println("8然后才进入无参构造");
    }//这里构造方法弹栈,弹栈之后就进行9地址赋值给变量
    
    public static void main(String[] args) {
        System.out.println("3进入main");
        TestSon p = new TestSon();//先进栈为p分配空间,再到堆为new TestSon()分配空间,并在对象空间中,对对象的(3)属性进行默认初始化(这里的属性默认初始化包括父类)
        System.out.println("9把new TestSon()对象的堆地址赋值给p变量");
    }
}
View Code

总结:

  1. 加载TestFather.class、TestSon.class文件进内存
  2. 在栈内存为p开辟空间
  3. 在堆内存为TestSon对象开辟空间
  4. 对TestSon对象的成员变量和父类的成员变量进行默认初始化
  5. 子类构造方法先进栈
  6. 父类构造方法后进栈
  7. 父类显示初始化属性
  8. 进入父类构造方法,父类构造弹栈
  9. 对TestSon对象的成员变量进行显示初始化
  10. 进入子类构造方法,子类构造弹栈
  11. TestSon对象初始化完毕,把对象地址赋值给p变量

多态

 技术分享图片

 技术分享图片

 

 引用类型变量指向多种不同类型的对象的例子如下:

技术分享图片

 

 引用类型p可以指向Person类型,Student类型,其他对象类型。

技术分享图片

 

多态虚拟方法的调用

 技术分享图片

例子:注意看注释

技术分享图片
//Person类
public class Person {//父类
    private int age;
    private String name;
    private int sex;
    
    public Person() {}
    public Person(int age,String name,int sex) {
        this.age = age;
        this.name = name;
        this.sex = sex;
    }
    
    public void showInfo() {
        System.out.println("父类的方法");
    }
}

//Student类
public class Student extends Person{
    private String school;
    
    public Student() {
        super(11,"猪头",1);
    }
    
    public void showInfo() {
        System.out.println("子类的方法,虽然引用类型e是Person类,但是方法是运行时才调用的,所以调用的是Student类的方法");
    }
    
    public static void main(String[] args) {
        Person e = new Student();
        //多态属性调用: 父类引用类型e调用子类属性,会报错,e是编译期类型,也就是Person类型
        e.school = "xxx";//这里报错,因为编译时e是Person类型的引用数据,不存在school属性
        e.showInfo();//这里会调用Student对象的方法,不会调用Person类的方法,因为方法是运行时才调用
        //注意多态调用子类方法时,父类需要存在和子类相同名字的方法,不然编译期报错。
    }
}
View Code

多态小总结:

 技术分享图片

技术分享图片

 

 多态性向上转型

技术分享图片
//Person类
    public void method(Person p) {
        p.showInfo();//如果传了一个Student对象过来,刚好子类重写了showInfo这个方法,那么就会调用子类的showInfo,否则调用父类的
    }
    public void showInfo() {
        System.out.println("父类的方法");
    }
}

//Student类
public class Student extends Person{

    public void showInfo() {
        System.out.println("子类的方法,虽然method的形参是Person类,但是方法是运行时才调用的,所以调用的是Student类的方法");
    }
    
    public static void main(String[] args) {
        Person p = new Person();
        Student s = new Student();

        p.method(s);//method的形参是Person父类,但是传了一个Student子类过去形成多态,刚好子类重写了method里面的showInfo方法,方法是运行期类型,所以当执行时,会执行子类里面的showInfo方法
    }
}
View Code

多态性向下转型

技术分享图片
//Person类
public class Person {//父类
    public void work() {
        System.out.println("工作");
    }
    
    public void hobby() {
        System.out.println("爱好");
    }

}

//Student类
public class Student extends Person{

    public void work() {
        System.out.println("学习");
    }
    
    public void hobby() {
        System.out.println("打篮球");
    }
    
    public void learn() {
        System.out.println("学生特有的学习方法");
    }
}

//Teacher类
public class Teacher extends Person{
    public void work() {
        System.out.println("教学");
    }
    
    public void hobby() {
        System.out.println("读书");
    }
    
    public void teach() {
        System.out.println("老师特有的教学方法");
    }
}


//Test测试类
public class Test {
    //多态的向下转型需要强转,在引用变量前加上(强转的类型)
    //多态的向下转型好处是避免了写多个类型的goWork方法,比如 goWork(Student s),goWork(Teacher t)。利用多态的向下转型,一下搞定,减少了代码的重复率
    public void goWork(Person p) {
        if(p instanceof Student) { //instanceof关键字判断  该引用变量  是否为该类型
            //如果要使用多个子类特有的方法,可以先把p类型先强制为Student类型,p=(Student)p;
            p.work();//work不是学生类特有的方法,所以不需要向下转型,这里为向上转型,自动调用重写的work方法,因为方法是运行期类型,所以会调用子类的work方法
            ((Student) p).learn();//learn为学生类特有的方法,父类Person没有这个方法,需要把形参Person类强转为Student类,才可以使用learn方法。
        }
        else if(p instanceof Teacher) {
            p.work();
            ((Teacher) p).teach();//teach也是Teacher子类特有的方法,想要编译期识别到teach方法,必须把p引用类型向下转型为Teacher类型。
        }
        else {
            p.work();
        }
    }
    public static void main(String[] args) {
        Test test = new Test();
        Student s = new Student();
        Teacher t = new Teacher();
        test.goWork(t);//把教师类传过去,goWork方法的形参是Person父类,自动构成多态的向上转型。
        test.goWork(s);//把学生类传过去,会使用学生类的
    }
}
View Code

Object类

技术分享图片

 技术分享图片

 

 Object顶级父类的方法应用例子:

技术分享图片
public static void main(String[] args) {
        
        Person p = new Person();
        Person p1 = new Person();
    
        //Object类的equals方法,判断是否同一个对象,不是指同一类。
        System.out.println(p.equals(p1));//false, p和p1是两个不同的对象,每次new都会在堆内存开辟空间,创建新的对象。p和p1都进行了new操作,所以p和p1都指向不同的内存地址。
        p1 = p;//进行赋值操作
        System.out.println(p.equals(p1));//true,上一条语句把p的内存地址赋值给p1,p1指向了p的内存地址,就是同一对象的意思。
        //说明:为社么equals是Object类的方法,但是Person类的p引用变量可以使用呢,因为Java所有的类默认继承Object类,Object类是所有Java类的父类,所有子类可以使用父类Object的方法.
        
        Object object = new Object();//创建Object类就是调用Object的构造方法
        System.out.println(object.hashCode());//输出object引用对象的哈希码
        System.out.println(object.toString());//toString是当前引用对象的地址,就是堆地址。
        //Object作为最顶级父类,可以使用多态接收子类的实例对象,比如:
        Object o = new Student();
        Object oj = new Person();
        //可以使用匿名对象使用Oject的方法
        System.out.println(new Student().toString());
    }
View Code

对象类型转换

技术分享图片

 

 数据类型转换例子:里面的引用类上面的练习有

技术分享图片
public class Test {
    public static void main(String[] args) {
        //基本类型转换
        int i = 10;
        long l = i;//小类型转成大类型,不用声明,自动转换
        
        long a = 10l;
        int b = (int)a;//大类型转小类型需要声明,强制转换
        
        //引用类型转换
        Student s = new Student();
        Person p = s;//从子类到父类的类型转换可以自动进行,向上转型
        
        Person p1 = new Person();
        Student s1 = (Student) p1;//从父类到子类的类型转换必须通过造型(强制类型转换)实现,向下转型

        Test t = new Test();
        Person p1 = t;//无继承关系的引用类型间的转换是非法的
        
        Object objPri = new Integer(5);//int的包装类型
        //所以下面代码运行时引发ClassCastException异常
        String str = (String)objPri;//这里运行时会报异常
        int b = new String();//基本类型不能和引用类型转换

        //Object是所有类的最高父类
        
        String s2 = "hello";
        Object obj = s2;//从子类到父类的类型转换可以自动进行
        System.out.println(obj);
        
        Object obj1 = "hello";
        
        String s3 = (String) obj1;//从父类到子类的类型转换必须通过造型(强制类型转换)实现
        
        System.out.println(s3);
    }
}
View Code

技术分享图片

 equals和==的区别

 技术分享图片

 

 技术分享图片

 例子:

技术分享图片
public class Test1 {
    public static void main(String[] args) {
        //==操作符
        //==基本类型比较:只要两个变量的值相等,即为true
        int i = 3;
        System.out.println(i == 3);//true
        
        //==引用类型比较:(是否指向同一个对象):只有指向同一个对象时,==才返回true
        //==比较的是所有的引用类型的地址,没有特殊情况
        //注意用 “==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错
        Person p1 = new Person();
        Person p2 = new Person();
        System.out.println(p1 == p2);//false,每次new操作都会产生新对象,分配堆内存地址给引用变量,p1和p2的引用变量里面存的内存地址不是同一个,即不是同一个对象
        p1 = p2;//这里把p2引用的内存地址赋值给p1,这时p1和p2同时指向同一内存地址,就是同一对象
        System.out.println(p1 == p2);//true,当为同一对象时,才会为true。==比较对象时,比较的是内存地址
        
        //equals()方法
        //equals方法只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。
        //特殊:但是equals方法对于类File、String、Date及包装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象
        //原因:在这些类中重写了Object类的equals()方法。
        String a = new String("a");String b = new String("a");
        int c = new Integer("1"); String d = new String("1");
        System.out.println(a.equals(c));//false , 虽然equals比较的是内容,但是引用类型不一致也会返回false
        System.out.println(a.equals(b));//true , equals对于特殊类比较的是内容
        System.out.println(a == b);//false , == 比较的是所有引用类型的引用地址
        //补充:如果你想改变某一个类的的equals方法,不想用equals比较地址,而是比较值,可以重写equals方法,注意记得加判断  是否为同一引用类型,再进行判断值,而且最好值放前面,如;"值".equals(变量),这种写法可以避免空指针    
    }
}
View Code

 

总结:比较基本数据类型相等用”==“,判断是否同一对象时最好也用”==“,虽然equals也可以判断同一对象,但是equals对File、String、Date和包装类是判断值的。

补充:如果你想改变某一个类的的equals方法,不想用equals比较地址,而是比较值,可以重写equals方法,注意记得加判断  是否为同一引用类型,再进行判断值,而且最好值放前面,如:"值".equals(变量),这种写法可以避免空指针。

String对象的创建

 技术分享图片

 例子:

技术分享图片
public class Test2 {
    public static void main(String[] args) {
        //字面值创建String对象
        String a1 = "a";
        String a2 = "a";
        String a3 = "a" + "b"; // 这里是直接在常量池中创建 "ab"对象,并返回常量池地址
        String a4 = "a" + "b";
        //字面值创建String对象,只会在字符串常量池中创建String对象,常量池在堆空间中
        //流程:首先会在常量池中判断是否存在字符串a对象,没有则创建,在常量池创建a对象后,返回a对象的常量池地址给a1
        //然后a2创建对象时,检测到常量池已经存在a对象,返回a对象的常量池地址给a2存储,这时a1和a2都指向a对象的常量池地址
        System.out.println(a1 == a2);//true,==判断常量池的地址
        System.out.println(a3 == a4);//true
        //new对象创建String对象
        String b1 = new String("b");
        String b2 = new String("b");
        //new对象创建String对象,会先在常量池中创建String对象,然后在堆空间再创建一个String对象,并返回的是堆空间的地址。
        //流程:首先会在常量池中判断是否存在字符串b对象,没有则创建,在常量池创建b对象后,然后在堆空间再次创建b对象,并返回b对象的堆内存地址给b1
        //然后b2创建对象时,检测到常量池已经存在b对象,则不在常量池创建b对象,只在堆空间创建b对象,返回堆空间的b对象的地址。
        System.out.println(b1 == b2);//false
        
        //new创建字符串拼接对象:是通过StringBulider实现的
        //流程:首先在字符串常量池中创建一个“1”对象,然后想再次在字符串常量池创建“1”对象时发现已经存在了“1”对象,两个字符串对象拼接完成后内容变成“11”,接着在堆空间创建“11”对象,并且返回“11”对象的地址给s3
        String s3 = new String("1") + new String("1");
        String s4 = new String("11");
        System.out.println(s3 == s4);//false

    }
}
View Code

注意:字面值创建String拼接对象只会在常量池中创建一个拼接对象,不会分别创建多个对象。

new String 创建String拼接对象,先去常量池分别创建多个对象,如果在常量池已经存在,则不创建,在常量池中创建完对象后,再进行拼接对象,最后在堆中创建一个拼接后的对象。最后强调一下:==是比较内存地址,equals对于String是比较值。

 练习

技术分享图片
public class Test3 {
    public static void main(String[] args) {
        int it = 65;
        float fl = 65.0f;
        System.out.println("65和65.0f是否相等?" + (it == fl)); //true ,基本类型判断不区分类型,只比较值

        char ch1 = ‘A‘; char ch2 = 12;
        System.out.println("65和‘A’是否相等?" + (it == ch1));//true,65是A的ASCII码
        System.out.println("12和ch2是否相等?" + (12 == ch2));//true

        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println("str1和str2是否相等?"+ (str1 == str2));//false,不是同一个对象

        System.out.println("str1是否equals str2?"+(str1.equals(str2)));//true,特殊情况,在String中equals是用来比较值的

//        System.out.println("hello" == new java.sql.Date()); //编译不通过
        
        //对象类型里面的值比较
        Person p1 = new Person();
        p1.name = "atguigu";//这里是对象里面的String类型赋值,这是字面值创建String,只在常量池中创建对象

        Person p2 = new Person();
        p2.name = "atguigu";//这里去字符串常量池创建对象,发现已存在,直接返回存在的对象的地址

        System.out.println(p1.name .equals( p2.name));//true,name属性是字符串
        System.out.println(p1.name == p2.name);//true,虽然两个person对象地址不一样,但是里面的String类型的值都是指向同一个常量池地址
        System.out.println(p1.name == "atguigu");//true,这里比较的是常量池地址

        String s1 = new String("bcde");

        String s2 = new String("bcde");
        System.out.println(s1==s2);//false,比较的是地址

    }
}
View Code

技术分享图片

技术分享图片
public class Order {
    private int orderId;
    private String OrderName;
    public Order() {}
    public Order(int orderId,String OrderName) {
        this.orderId = orderId;
        this.OrderName = OrderName;
    }
    
    
    public int getOrderId() {
        return orderId;
    }
    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    public String getOrderName() {
        return OrderName;
    }
    public void setOrderName(String orderName) {
        OrderName = orderName;
    }
    
    //重写equals方法判断对象之前是否属性的值全一致
    public boolean equals(Object obj) {
        boolean flag = false;
        //判断对象是否为同一类型
        if(obj instanceof Order) {
            Order o = (Order)obj;//强制为Order类型
            //判断id/name里面的值是否一致
            if(o.getOrderId() == this.getOrderId() && o.getOrderName().equals(this.getOrderName())) {
                flag = true;
            }
        }
        return flag;
    }
    public static void main(String[] args) {
        Order o1 = new Order(111,"a");
        Order o2 = new Order(111,"a");
        System.out.println(o1.equals(o2));//true,里面的值一致
    }
}
View Code

 2.请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖equals方法,使其判断当两个MyDate类型对象的年月日都相同时,结果为true,否则为false。    public boolean equals(Object o)

技术分享图片
public class MyDate {
    private int year;
    private int month;
    private int day;
    
    public MyDate() {}
    public MyDate(int year,int month,int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    
    @Override
    public boolean equals(Object obj) {
        boolean flag = false;
        if(obj instanceof MyDate) {
            MyDate date = (MyDate)obj;
            if(date.year == this.year && date.month == this.month && date.day == this.day) {
                flag = true;
            }
        }
        return flag;
    }
    
    public static void main(String[] args) { 
        MyDate d1 = new MyDate(2019,12,12);
        MyDate d2 = new MyDate(2019,12,12);
        System.out.println(d1.equals(d2));//true,比较的是值,如果值一致则代表一样
    }
}
View Code

toString()方法

技术分享图片

 

 例子

技术分享图片
        MyDate ss = new MyDate(2018,12,12);
//        创建对象时,打印引用对象的值,都是内存地址,如果想打印对象的信息,就需要重写toString()方法
        /**
         * 重写MyDate类的toString()方法
         * @Override
            public String toString() {
                return "MyDate [year=" + year + ", month=" + month + ", day=" + day + "]";
            }
         */
        System.out.println(ss);//org.chen.day08.MyDate@54bedef2,重写toString()方法后,打印出MyDate [year=2018, month=12, day=12]
View Code

包装类

 技术分享图片

基本数据类型包装成包装类的实例    ---装箱

 技术分享图片

 

 获得包装类对象中包装的基本类型变量    ---拆箱

技术分享图片

 例子:

技术分享图片
    //装箱
        Boolean b = new Boolean(false);//boolean类的包装类
        Integer i = new Integer(12);//int类的包装类
        Long lo = new Long(33);//long类的包装类
        Character ct = new Character(‘a‘);//char类的包装类
        Float f = new Float(11);//float类的包装类
        Double d = new Double(55);//double类的包装类
        //注意:除了char和int的包装类区别明显,其他都是首字母大写,所以有可能不小心使用到包装类,最常见就是Boolean和boolean用错
        
        //拆箱,拆箱方法:包装类.基本数据类型Value(),如下所示
        boolean b1 = b.booleanValue();
        int i1 = i.intValue();
        double db1 = d.doubleValue();
        
        //jdk1.5版本后,已经支持自动装箱/拆箱了,前提是基本数据类型要和包装类型一致,如:int和Integer
        //自动装箱
        //由于支持了自动装箱,所以有时候想用基本数据类型,但是错用包装类,但是不会报错,因为是属于自动装箱
        Boolean b2 = false;//注意这里是boolean的包装类
        Integer in = 32;//自动装箱
        
        //自动拆箱
        boolean bz = b2;//这里不需要用到手动的拆箱方法了
        int in2 = in;//自动拆箱,存放到基本数据类型中
View Code

字符串转换位基本数据类型

技术分享图片

技术分享图片
//把字符串转为基本数据类型
        //1、通过包装类把字符串转为int包装类型,然后拆箱赋值给基本数据类型int
        int cc = new Integer("1234");
        float ff = new Float("322.9");
        boolean bls = new Boolean("true");
        System.out.println(bls);
        //2、通过包装类的parseXXX()方法把里面的字符串转为基本数据类型
        int ccs = Integer.parseInt("232");
        boolean bsl = Boolean.parseBoolean("false");
View Code

基本数据类型转换为字符串

技术分享图片

技术分享图片
//基本数据类型转字符串
        //1、通过String.valueOf()方法把基本数据类型转为字符串,所有基本数据类型都可以
        String booleans = String.valueOf(true);
        String ints = String.valueOf(123);
        String doubles = String.valueOf(32.2);
        //2、字符串拼接直接变成字符串,注意只有+字符串的时候才算是字符串拼接,如果前面都是数字相加+就会运算结果,遇到+“”才会开始拼接字符串,也就是转换为字符串
        String te = 23 + "";
        String ds = 32.1 + "";
        String we = true + "";
        System.out.println(we);//这里输出的true只是字符串,不是boolean的true
View Code

8java继承、方法重写、权限修饰符、super关键字、对象实例化过程、多态、Object类、包装类

原文:https://www.cnblogs.com/unlasting/p/12393979.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!