java面向对象基础(二)

*/

.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}

.hljs-comment,
.hljs-template_comment,
.diff .hljs-header,
.hljs-javadoc {
color: #998;
font-style: italic;
}

.hljs-keyword,
.css .rule .hljs-keyword,
.hljs-winutils,
.javascript .hljs-title,
.nginx .hljs-title,
.hljs-subst,
.hljs-request,
.hljs-status {
color: #333;
font-weight: bold;
}

.hljs-number,
.hljs-hexcolor,
.ruby .hljs-constant {
color: #099;
}

.hljs-string,
.hljs-tag .hljs-value,
.hljs-phpdoc,
.tex .hljs-formula {
color: #d14;
}

.hljs-title,
.hljs-id,
.coffeescript .hljs-params,
.scss .hljs-preprocessor {
color: #900;
font-weight: bold;
}

.javascript .hljs-title,
.lisp .hljs-title,
.clojure .hljs-title,
.hljs-subst {
font-weight: normal;
}

.hljs-class .hljs-title,
.haskell .hljs-type,
.vhdl .hljs-literal,
.tex .hljs-command {
color: #458;
font-weight: bold;
}

.hljs-tag,
.hljs-tag .hljs-title,
.hljs-rules .hljs-property,
.django .hljs-tag .hljs-keyword {
color: #000080;
font-weight: normal;
}

.hljs-attribute,
.hljs-variable,
.lisp .hljs-body {
color: #008080;
}

.hljs-regexp {
color: #009926;
}

.hljs-symbol,
.ruby .hljs-symbol .hljs-string,
.lisp .hljs-keyword,
.tex .hljs-special,
.hljs-prompt {
color: #990073;
}

.hljs-built_in,
.lisp .hljs-title,
.clojure .hljs-built_in {
color: #0086b3;
}

.hljs-preprocessor,
.hljs-pragma,
.hljs-pi,
.hljs-doctype,
.hljs-shebang,
.hljs-cdata {
color: #999;
font-weight: bold;
}

.hljs-deletion {
background: #fdd;
}

.hljs-addition {
background: #dfd;
}

.diff .hljs-change {
background: #0086b3;
}

.hljs-chunk {
color: #aaa;
}

#container {
padding: 15px;
}
pre {
border: 1px solid #ccc;
border-radius: 4px;
display: block;
background-color: #f8f8f8;
}
pre code {
white-space: pre-wrap;
}
.hljs,
code {
font-family: Monaco, Menlo, Consolas, ‘Courier New‘, monospace;
}
:not(pre) > code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
white-space: nowrap;
border-radius: 4px;
}
-->

权限修饰符

权限修饰符包括public、private、protected和不加任何修饰符的default,它们都可以修饰方法和变量。其中public和默认的default(不加任何修饰符)这两个还可以修饰class。private和protected修饰类的情况只能在使用内部类时修饰,正常情况下不能使用这两个修饰符修饰类。

(1).public:用public修饰的变量及方法,包内及包外的任何类(包括子类和普通类)均可以访问;
(2).protected:用protected修饰的变量及方法,包内的任何类及包外那些继承了该类的子类才能访问,protected重点突出继承;
(3).default:没有用public、protected及private中任何一种修饰,其访问权限为default默认权限。默认访问权限的类、类属变量及方法,包内的任何类(包括继承了此类的子类)都可以访问它,而对于包外的任何类都不能访问它(包括包外继承了此类的子类)。default重点突出包;
(4)private: 用private修饰的变量及方法,只有本类可以访问,而包内包外的任何类均不能访问它。

就一句话:protected修饰符所修饰的变量和方法,只可以被子类访问,而不管子类是不是和父类位于同一个包中。default修饰符所修饰的变量和方法,只可被同一个包中的其他类访问,而不管其他类是不是该类的子类。protected属于包修饰符,还是子类修饰符,而default属于包修饰符。

从权限严格角度来说,private < default < protected < public

在考虑default修饰的权限时,它是包修饰符,其中没有加入到包中的"裸体类"属于同一个隐式的包中,因此可以互相访问。

例如,前面的person和student的继承关系中,将父类成员变量name加上private修饰符,于是下面的代码将编译出错。因为new子类对象时,构造方法中赋值给this.name,而这个name是继承自父类的,它是private的。因此对于子类来说,这个成员变量属于能看到,不能引用、不能操作的摆设属性。

class Person  {
    private String name;
    int age;

}

class Student extends Person {
    int studentID;

    Student(int id,String name,int age) {
        this.name = name;
        this.age = age;
        this.studentID = id;
    }

}

public class Inherit {
    public static void main(String[] args) {
        Student s1 = new Student(1,"Malongshuai",23);
    }
}

方法的重写(overwrite/override)

父类定义的成员相对来说都比较粗糙,当子类继承时,难免无法适当地描述子类。因此当子类对从父类继承的方法不满意时,可以重写方法。

例如Person类能eat(),但girl类吃饭是淑女的吃,boy类吃饭是粗鲁的吃。girl类很不满意,因为父类的eat()只能描述吃,不能描述怎么吃。于是girl类就重写eat()方法,让吃这个方法符合自身的淑女形象。

重写方法必须和被重写的方法具有相同的方法名称、参数列表和返回类型。重写的方法不能比被重写的方法权限更严格。从方法访问的角度来说,父类的方法都能被访问,子类重写后的方法却不能被访问,这显然是不合理的,且即使这是能访问父类方法,但重写的意义就丢失了。

重写方法时,最佳实践方式是copy整个被重写的方法的定义语句。因为即使重写方法的名称改变了,编译也不会出错。例如重写eat()结果写成了Eat(),编译是不会有任何错误出现的,此时它没有重写,而是新定义了一个Eat()方法。

class Person  {
    String name;
    int age;

    void eat() { System.out.println("eating...");}
}

class Student extends Person {
    int studentID;

    Student(int id,String name,int age) {
        this.name = name;
        this.age = age;
        this.studentID = id;
    }

    void eat() { System.out.println("graceful eating");}  //重写
    void study() {System.out.println("studing...");}
}

public class Inherit {
    public static void main(String[] args) {
        Student s1 = new Student(1,"Malongshuai",23);
        System.out.println(s1.studentID+","+s1.name+","+s1.age);
        s1.eat();  //调用重写后的eat方法
    }
}

super关键字

this关键字指向对象自身,而super关键字则指向对象中的父对象。如下图:

super既可以用来引用父对象的成员变量,也可以用来调用父对象的方法。例如下面的代码:

class FatherClass {
    public int value;
    public void f(){
        value = 100;
        System.out.println("FatherClass.value="+value);
    }
}

class ChildClass extends FatherClass {
    public int value;
    public void f() {
        super.f();       //虽然f()要重写,但父对象的f()函数还有一些用武之地来发挥余热
        value = 200;
        System.out.println("ChildClass.value="+value);
        System.out.println(value);
        System.out.println(super.value);
    }
}

public class TestInherit {
    public static void main(String[] args) {
        ChildClass cc = new ChildClass();
        cc.f();
    }
}

new出子对象时,父类和子类中都有value属性,它们都采用的初始化值0。当执行cc.f()时,调用子类的f()方法,该方法首先调用父对象的f()方法,父f()方法先将value赋值为100,这个value是父对象的属性,然后回到子f()中赋值value为200,这个value是子对象自身的value,随后输出的两个value都是子对象中的value属性,最后的super.value是父对象中的value属性。

虽然在图中看上去super和this的地位是相同的,但实际上它们之间很不公平,不公平之处在于有引用变量(上图中的cc)指向子对象,所以能够使用"return this"代码来返回一个子对象,但却不能使用"return super"来返回子对象中的父对象,因为没有引用变量指向父对象。

关于super调用的成员变量,需要区分清楚是子对象中的属性还是父对象中的属性。如果子对象和父对象中有同名属性var,在没有指定"this.var"和"super.var"时,仅模糊地指定var时将优先取子对象的属性,如果子对象中没有某属性,则var表示的是父对象中的属性。例如:

class Student extends Person {
    int studentID;
    int age = 33;

    Student(int id) {
        this.name = super.name + "x";
        this.age = age + 2;   //右边的age是子对象的属性,但如果将"int age = 33;"注释,则age是父对象的属性
        this.studentID = id;
    }
}

继承时构造方法的重写super()

子对象中总是包含父对象,这个父对象是怎么来的?对象都是通过构造方法构造出来的,因此在new子类对象的时候,会调用对应的子类构造方法构造子对象,正是这个时候使用super()方法表示调用父类构造方法将父对象构造出来的。

在写构造父对象的代码时有以下几个规则:

  1. 使用子类构造方法构造子对象时,必须要构造父对象。
  2. 子类可以在自己的构造方法中使用super(args)来调用父类的构造方法。同理,可以使用this(args)来调用本类其他的构造方法。
  3. super(args)必须写在子类构造方法中的第一行,因为要先构造出父对象,再慢慢填补子对象自身。如果没有显式书写super(args),则默认在第一行处调用父类无参数的构造方法,等价于super()。
  4. 如果子类构造方法中调用的super(args)在父类中不存在对应参数列表的构造方法,则编译错处。这包括没有显式指定super()时,且父类又重载了构造方法使得父类中没有了无参数的构造方法时。
class Person {
    String name;
    int age;

    Person() {
        System.out.println("Person()");
    }

    Person(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person(arg1,arg2)");
    }

    Person(String name) {
        this.name = name;
        age = 20;
        System.out.println("Person(arg1)");
    }
}

class Student extends Person {
    int studentID;

    Student(int id) {
        super("Malongshuai",23);   //第一行调用父类构造方法构造父对象,且是含有两个参数的Person(arg1,arg2)
        this.name = super.name + "X"; //调用父对象中的name属性
        this.age = age + 2;           //也是调用父对象中的属性age
        this.studentID = id;
    }
}

public class TestSuper {
    public static void main(String[] args) {
        Student s1 = new Student(1);
        System.out.println(s1.studentID+", "+s1.name+", "+s1.age);
    }
}

如果将"super("Malongshuai",23);"修改为super("Malongshuai"),则表示调用父类的Person(arg1)构造方法。如果改为super(),则表示调用父类的Person()构造方法。如果省略不写super,则等价于super()。

Object类

除了明确定义了从某个父类继承的子类,java中的所有类都是从java.lang包中的Object类继承来的。也就是说,Object类是所有类继承的根,也就是它们的祖宗。一级继承一级,最终的根总是Object类。

这个类里提供了几个方法,但基本上所有方法都建议重写,因为它的级别太高,抽象化的太严重,它的提供的那些方法也就太大众化。

toString()

在和对象做数据连接时,将自动调用该类的toString()方法。例如System.out.println("Hello" + Person)时,等价于System.out.println("Hello" + Person.toString())

例如:

public class TTString {
    public static void main(String [] args) {
        Person p = new Person();
        System.out.println(p);
        System.out.println(p.toString());
    }
}

class Person {}

编译并运行,查看toString()的运行结果。

D:\myjava
λ javac TTString.java

D:\myjava
λ java TTString
Person@15db9742
Person@15db9742

toString()的结果是"类名@hex(hashcode)"。官方建议,任何子类都应该重写该方法。例如:

public class TTString {
    public static void main(String [] args) {
        Person p = new Person();
        System.out.println(p);
    }
}

class Person {
    public String toString() {  //重写toString()
        return "Hello World";
    }
}

对象的比较"=="和equals()

对象与对象之间是否有相等关系?一般可以认为,如果两个对象的对象内容完全相同,将认为是相等的对象。

在进行对象比较时,"=="比较的是两个对象的引用地址,因此两个对象使用"=="比较时是绝对不会相等的。Object类中的equals(),基本等价于"==",因此也无法正确比较对象是否相等。所以官方手册建议重写equals()方法。在String类中已经重写好了。

例如,使用String类中的equals()。

public class TTequals {
    public static void main(String [] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

final关键字

final表示最终的意思,它可以修饰变量、方法和类。

  1. final变量的值不能被改变。

    • (1).final的成员变量不可改变。
    • (2).final的局部变量和形参不可改变。
  2. final的方法不能被重写。
  3. final的类不能被继承。

也就是说,要想让变量只读、方法不可改变或类的继承到此结束,就用final进行修饰。

注:若您觉得这篇文章还不错请点击右下角推荐,您的支持能激发作者更大的写作热情,非常感谢!

原文地址:https://www.cnblogs.com/f-ck-need-u/p/8127546.html

时间: 2024-10-16 15:42:56

java面向对象基础(二)的相关文章

Java面向对象基础二

1.对象的使用方法 2.多对象的创建方法 3.匿名对象的创建和使用方法

【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder

[喵"的Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder 1.String String是Java中的一个final类,主要用于字符串的处理. 1.1 不可变性 String内的字符串是不可变的,每一次修改都会重新生成一个新的String对象实例. 例: 1 // 在堆中会创建一个"Hello"字符串实例,把地址赋给对象a 2 String a = new String("Hello&

【Java面向对象基础(一)】数据类型与运算符

[喵"的Android之路][基础篇(一)][Java面向对象基础]数据类型与运算符 1.数据类型介绍 在Java中,数据类型分为两种:基本数据类型和引用类型. 基本数据类型共8种,见下表: 基本数据类型 字节数 二进制位数 最小值 最大值 默认值 byte 1 8-bit -2^7 +2^7 - 1 0 short 2 16-bit -2^15 +2^15 - 1 0 int 4 32-bit -2^31 +2^31 - 1 0 long 8 64-bit -2^63 +2^63 - 1 0

【Java面向对象基础(三)】面向对象思想

[喵"的Android之路][基础篇(三)][Java面向对象基础]面向对象思想 1 面向对象的WWH 1.1 What--什么是面向对象 首先,要理解“对象”.在Thinking in Java中提到“Everything is an object”,即万物皆对象.这里的“对象”指的是任何实体或者任何可以当作实体看待的“虚幻的事物”.比如现实中的人(男人.女人.老人.小孩而...).动物(大象.狮子.猴子...).桌子.凳子.汽车.ATM机等等,也可以使看不见摸不着的空气(氧气.二氧化碳.氮气

关于JAVA面向对象基础整理以及个人的理解(适合初学者阅读)

JAVA的基础语法等都跟C有很大的相似之处,所以这里就不多啰嗦了.直接从数组开始. 数组: 1.声明 int [] a; 在声明的过程中,并没有分配空间给数组.我们可以在声明的同时,用new来分配相应的空间 int [] a = new int[100]; 这里开辟了一个空间为100大小的数组,内存分配也完成了. 我们可以在声明的同时也确定元素个数 int [] a = new int[]{1,3,5,7,9}; 面向对象(重点) class Human{ int height; void br

Java面向对象(二、封装)

Java 继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. 生活中的继承: 兔子和羊属于食草动物类,狮子和豹属于食肉动物类. 食草动物和食肉动物又是属于动物类. 所以继承需要符合的关系是:is-a,父类更通用,子类更具体. 虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自

IO输入输出流——Java面向对象基础(29)

一.概念 IO(输入输出流) InputStream 输入流 OutputStream 输出流   输入输出流广义上就是物理存储介质.设备.容器数据的传输过程.   Java中提供一个强大的api操作IO,java.io包 二.常见的File类 File常常用于操作系统文件或目录,其中常用的方法务必掌握. File file = new File("填写文件|文件目录的路径"); createNewFile()  创建文件 delete()   删除文件或目录 exists()  判断

Java学习 &#183; 初识 面向对象基础二

Package 为什么需要使用package a)   解决类重名的问题 b)   便于管理类 怎么使用package a)   类的第一句非注释性语句 b)   命名:域名倒着写,再加上模块名 注意事项 a)   不要使用默认包 JDK主要包 Import 1.为什么需要使用包 2.import怎么使用 3.注意事项 4.静态导入 原文地址:https://www.cnblogs.com/secoding/p/9495903.html

java面向对象基础知识

一.面向对象与面向过程的区别: ①所处的角色不同:前者指挥者,后者执行者:②所需知道的事情不同:前者知道哪些是做这些事情的人就可以,不需了解具体的事情操作的过程.后者需要具备应有的技能来做这些事情. 二.面向对象的基本操作过程 指挥者采用面向对象思想,通过创建类,来创建统一的属性值[成员属性]和(做事的)方法[成员方法]. 通过创建的类或者jdk已有的类,来创建具体的对象,属性值明确,方法明确. 举例:创建类 1 package com.oracle.demo02; 2 3 public cla