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()方法表示调用父类构造方法将父对象构造出来的。
在写构造父对象的代码时有以下几个规则:
- 使用子类构造方法构造子对象时,必须要构造父对象。
- 子类可以在自己的构造方法中使用super(args)来调用父类的构造方法。同理,可以使用this(args)来调用本类其他的构造方法。
- super(args)必须写在子类构造方法中的第一行,因为要先构造出父对象,再慢慢填补子对象自身。如果没有显式书写super(args),则默认在第一行处调用父类无参数的构造方法,等价于super()。
- 如果子类构造方法中调用的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表示最终的意思,它可以修饰变量、方法和类。
- final变量的值不能被改变。
- (1).final的成员变量不可改变。
- (2).final的局部变量和形参不可改变。
- final的方法不能被重写。
- final的类不能被继承。
也就是说,要想让变量只读、方法不可改变或类的继承到此结束,就用final进行修饰。
注:若您觉得这篇文章还不错请点击右下角推荐,您的支持能激发作者更大的写作热情,非常感谢!
java面向对象基础(二)的更多相关文章
- Java面向对象基础二
1.对象的用法 2.多对象的创建方法 3.匿名对象的创建和用法
- 【重走Android之路】【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder
[重走Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder 1.String String是Java中的一个final ...
- 【重走Android之路】【Java面向对象基础(一)】数据类型与运算符
[重走Android之路][基础篇(一)][Java面向对象基础]数据类型与运算符 1.数据类型介绍 在Java中,数据类型分为两种:基本数据类型和引用类型. 基本数据类型共8种,见下表: 基本数 ...
- 【重走Android之路】【Java面向对象基础(三)】面向对象思想
[重走Android之路][基础篇(三)][Java面向对象基础]面向对象思想 1 面向对象的WWH 1.1 What--什么是面向对象 首先,要理解“对象”.在Thinkin ...
- 086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结
086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结 本文知识点:面向对象基础(类和对象)总结 说明 ...
- 085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用
085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用 本文知识点:构造方法调用 说明:因为时间紧张,本人写博客过程中只是 ...
- 084 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 03 构造方法-this关键字
084 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 03 构造方法-this关键字 本文知识点:构造方法-this关键字 说明:因为时间紧 ...
- 083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法
083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法 本文知识点:构造方法-带参构造方法 说明:因为时间紧张, ...
- 082 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 01 构造方法-无参构造方法
082 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 01 构造方法-无参构造方法 本文知识点:构造方法-无参构造方法 说明:因为时间紧张, ...
随机推荐
- Spring框架入门之开发环境搭建(MyEclipse2017平台)
基于MyEclipse2017平台搭建Spring开发环境,这里MyEclipse已将Spring集成好了,我们只需要做一简单配置即可 一.环境配置 OS:Windows7 64位 IDE工具:MyE ...
- 卸载CentOS7-x64自带的OpenJDK并安装Sun的JDK7的方法
第一步:查看并卸载CentOS自带的OpenJDK 安装好的CentOS会自带OpenJdk,用命令 java -version ,会有下面的信息: java version "1.6.0& ...
- 80、Flask用法简析
本篇导航: 基本使用 模板.请求和响应 Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于 ...
- 腾讯windows系统服务器
今天用腾讯的服务器搭建起了自己的博客,先看主页效果...简单的ui设计,主要就是要上服务器看看. 说说服务器的搭建: 1.卖,进腾讯云,自己对应的买操作系统的就可以的啦.具体的链接: https ...
- SPI通讯协议
一.SPI概述 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线, ...
- Java中的集合框架(下)
学生选课--判断Set中课程是否存在 package com.imooc.collection; import java.util.ArrayList; import java.util.Arrays ...
- golang 在 windows 下编译出 linux 二进制可执行文件的软件套装合集 [go 1.7.3环境]
golang 很好用,不过要把工具链弄完整. 要不你会发现怎么不能编译跨平台的呀? 怎么写代码没提示啊? ... 这一整套弄下来并不容易. 所以精心准备了一套工具方便大家使用. 软件列表如图. 安装顺 ...
- 【JavaScript_DOM 淘宝购物车】
让我们一起看一下淘宝的购物车是怎么做的吧,刚刚入门的我可能很多地方的用法都不够优化,不过个人感觉先把逻辑清晰之后再做的话其实也并不难哦, 以下是我做的页面代码: HTML代码: <!DOCTYP ...
- UVALive 3882 - And Then There Was One【约瑟夫问题】
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- codeforce 367dev2_c dp
codeforce 367dev2_c dp 标签: dp 题意: 你可以通过反转任意字符串,使得所给的所有字符串排列顺序为字典序,每次反转都有一定的代价,问你最小的代价 题解:水水的dp...仔细想 ...