JAVA知识总结(三):继承和访问修饰符
今天乘着还有一些时间,把上次拖欠的面向对象编程三大特性中遗留的继承和多态给简单说明一下。这一部分还是非常重要的,需要仔细思考。
继承
继承:它是一种类与类之间的关系,通过使用已存在的类作为基础来建立新类。其中已存在的类称为父类(或基类); 建立的新类称为子类(或派生类)。简单的就是子类继承父类的非私有属性和方法。
需要注意的是,新定义的类可以选择继续使用父类的功能或者自己增加新的数据或新的功能,但不能选择性地继承父类。(要么继承所有(前提是非私有),要么就不继承)
只要能满足 "A is a B"的关系就可以形成继承关系,代码中是通过 extends 关键字来实现继承的。
特别注意:在java中只能继承一个父类(也就是单继承),而且子类可以访问父类的非私有成员。这个和Python不一样,Python的继承可就灵活了。
我们知道子类继承了父类之后,可以访问父类的非私有成员;但是父类的私有成员,子类还是无法直接访问。如果我们想访问呢?可以通过父类暴露的公有方法来实现间接访问。
父类对象不可以访问到子类特有的方法或属性,同时父类不可以访问子类特有成员(那怕是公有的成员)
重载
方法重载必须同时满足以下条件:
- 同一个类中;;
- 方法名相同,参数列表不同(参数顺序、个数、类型);
- 方法返回值、访问修饰符任意;
- 与方法的参数名无关。
public void printinfo() {
System.out.println("方法重载1");
};
public void printinfo(String name) {
System.out.println("方法重载2");
};
public String printinfo(String name, int age) {
return "方法重载3";
};
public String printinfo(String age, String name) {
return "方法重载4";
};
public String printinfo(int age, String name) {
return "方法重载5";
};
// 与方法的参数名无关,加上下面的代码会和上面的 printinfo(int age, String name)造成重复而报错:
public String printinfo(int size, String name) {
return "方法重载5";
};
重写
方法重写也必须同时满足以下条件:
1、在满足继承关系的子类中;
2、方法名相同,参数列表相同(参数顺序、个数、类型);
3、方法返回值相同或者是子类类型(但不允许是Object类型,可以向下兼容,向上是不可以的);
4、访问修饰符的限定范围大于等于父类方法。
(一大两小,子类的访问修饰符的限定范围大于等于父类;子类的返回值类型和异常都需要小于等于父类)
注意:在子类中是可以定义与父类重名的属性的,但这并不说明属性是可以重写的。
访问修饰符
在Java里面一共包含4种访问修饰符,分别是:
1、private:私有的;
2、默认;
3、protected:受保护的;
4、public:公共的。
其中,private:只允许在本类范围中进行访问,离开了当前类就不允许访问;
默认: 允许在当前类,同包子类/非子类都可调用,跨包子类/非子类都不允许;
protected:允许在当前类,同包中的子类/非子类都可以以及跨包子类调用。跨包的非子类不允许调用。
public:允许在任意位置访问。
按照前面的顺序,自上而下,访问范围越来越大;自下而上,限制能力越来越强:
(同包包括同包子类与非子类;子类包括同包子类和跨包子类)
访问修饰符对方法重写的影响
子类重写父类方法时,访问修饰符是允许改变的,要求是: 子类的访问范围必须大于等于父类的访问范围。也就是说如果父类访问修饰符是public,那么子类的访问修饰符也必须是public,其他的类似。
继承的初始化顺序
继承后的初始化顺序如下:
父类静态成员 -> 子类静态成员 -> 父类对象的构造 -> 子类对象的构造
(父类静态成员 -> 子类静态成员 -> 父类对象的构造->父类的构造方法 -> 子类对象的构造->子类的构造方法)
一个问题: 访问修饰符影响成员加载顺序?静态成员优先于静态代码块执行?
访问修饰符不影响成员加载顺序,跟书写位置有关。如果把静态代码块写在静态变量的前面,那么先执行静态代码块。
super关键字
如果子类继承并重写了父类的方法,那么我们通常调用的就是重写后的子类方法。如果需要调用父类的方法,我们可以使用super.方法
来达到这个目的。
当然也可以使用super.属性
来达到访问父类的非私有属性的目的。
尽管父类的构造方法的访问修饰符是public,但是它却不可以被子类继承和重写的。
虽然它两个不可以,但是它的存在却是非常必要的,因为子类对象的实例化要依赖于父类对象的构造方法(默认,无参或有参的构造方法)。
如果子类调用了自己有参的构造方法,而父类定义了有参和无参的构造方法,程序依然是调用父类无参的构造方法。也就是说,我们在子类的构造方法中没有显式标注的情况下,默认调用父类的无参构造方法,因此父类的无参构造方法很重要,一定要写,否则会影响子类的对象实例化。
如果子类构造方法中既没有显式标注,且父类中没有无参的构造方法,则引发编译错误。
我们可以使用super(参数)
这种形式来调用父类允许被访问的其他构造方法,但是此时super()必须放在子类构造方法有效代码的第一行(必须是子类的构造方法(其他方法不行)的第一行(其他行不行))。
也就是说父类在实例化的时候会默认调用无参的构造方法(此时你不定义无参的构造方法是可以的),但是如果子类在实例化对象的时候没有显示标志(也就是会默认调用父类无参的构造方法),而此时父类其实是不存在无参的构造方法,所以会引发编译错误。
this和super的对比
this:当前类对象的引用:
1、访问当前类的成员方法;
2、访问当前类的成员属性;
3、访问当前类的构造方法;
4、不能在静态方法中使用;
super:父类对象的引用:
1、访问父类的成员方法;
2、访问父类的成员属性;
3、访问父类的构造方法;
4、不能在静态方法中使用;
注意:在调用构造方法时,this和super不能同时存在(前面说过两者都要求在第一行)。
Object类
Object类是所有类的父类,这个其实和Python中差不多,在Python里面也是所有的类都继承于object这个基类。点这直接查看api:javase8api
一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)。
Class Object is the root of the class hierarchy.
Every class has Object as a superclass.
All objects, including arrays, implement the methods of this class.
Object类存放于java.lang包中,这个包系统默认会为我们直接加载。
equals用法
如果子类没有重写Object类的equals方法,那么比较的是两个引用是否指向同一个地址;而String类则重写了Object类的equals方法,所以比较的是字符串的值是否相等。(言外之意,子类可以通过重写equals方法的形式,改变比较的内容)
因此我们不能这样说equals比较的两个对象的值,或者引用地址,但是我们却可以说"=="比较的却一定是两个对象的引用地址。
toString用法
api告诉我们,toString最后返回的是下面这种形式:(包名.类名@内存中的哈希码)
getClass().getName() + '@' + Integer.toHexString(hashCode())
同样的,子类如果没有重写Object类的toString方法,那么则会打印输出其在内存中的哈希码;而String类则重写了Object类的toString方法,所以打印输出其真实值。(言外之意,子类可以通过重写toString方法的形式,改变输出的内容)
还要说明的一点就是输出对象
和对象.toString
的效果是一样的,因为直接输出对象的时候其实是调用了对象.toString方法。
Final关键字
当我们不希望某些类被继承,某些方法被重写或者某些数据被修改时,可以使用final关键字来实现这个目的。
如果某个类被final修饰,则表明该类不可以被继承,该类没有子类,public final class/final public class都可以,只要是放在class的前面就可以;
如果某个方法被final修饰,则表明该方法不可以被重写,但是并不影响子类去继承调用它(final不可以修饰构造方法)。
如果某个局部变量被final修饰,那么我们可以不用在声明的同时立马进行赋值,但是必须在使用之前进行赋值,一旦赋值就不能被修改;
(方法内的局部变量的作用范围,从该行开始到所在大括号结束;而类的成员变量的作用范围取决于它前面的访问修饰符);
如果某个成员变量被final修饰,我们同样不需要声明的同时进行立马赋值,但是必须在使用之前进行赋值,而且只能在构造方法或者类代码块(构造代码块)中进行赋值,一旦赋值就不能被修改;也就是说类中成员属性的赋值可以有三种方式: 1. 定义是直接初始化; 2. 构造方法; 3. 构造代码块(类代码块)。
注意: 当具有多个构造方法时,final关键字修饰的成员变量如果选择了在构造方法里面进行赋值,那么就需要在所有的构造方法里面进行赋值,但是不同构造方法是可以赋不同值的
final对数据类型的影响
我们知道java 数据类型分为基本数据类型(byte,short,int,long,float,double,char,boolean) 和 引用数据类型(array,String,interface,自定义的类...)
基本数据类型是可以直接进行赋值的,而引用类型需要实例化该类的对象,然后才能给其对象进行赋值(String这个比较特殊,两种形式都是可以的)
我们知道基本数据类型在内存中存放的是数据本身,而引用数据类型在内存中存放的则是对象的引用地址。
下面的例子告诉我们,被final修饰的对象不可以修改它的引用地址,但是属性却是可以的:
final Test test=new Test("hello");
// test=new Test ();
Test.key="world";
总结一下就是:基本数据类型的变量其一旦被赋初值,就无法进行修改;而引用类型的变量只是在初始化之后不能再指向另一个对象,但是对象的内容却是可变的。
因此final可配合static使用,用来修饰方法和变量。通常是用于修饰配置信息等(因为这类信息只需要加载一次,而且后面不需要被修改)。言外之意,使用final修饰可以提高性能,但会降低可扩展性。
普通代码块,类代码块,构造代码块,静态代码块区别
代码块都是一对大括号{}所括起来的内容。
普通代码块就是一对大括号{}所括起来的内容,只存在于类的方法之中;
类代码块和构造代码块是一个东西,就是直接在类中进行定义的,前面没有static进行修饰。构造代码块在创建对象时被调用,每次创建对象都会被调用,并且构造代码块的执行次序优先于类的构造方法。
静态代码块前面有static关键字进行修饰,它不能存在于任何方法体内,也不能直接访问实例变量和实例方法,需要通过类的实例对象来访问。
通常我们new一个对象,JVM要经过这样的初始化顺序:父类静态块>子类静态块>父类属性>父类构造器>子类属性>子类构造器,这一系列的工作会消耗大量的内存和cpu。
具体的研究可以参看这里:详解java中的四种代码块。
java中的注解
注解是JDK1.5版本引入的一个特性, 它可以声明在包、类、属性、方法、局部变量、方法参数等前面,作用就是对这些元素进行说明、注释。
按照运行机制来分类
注解按照运行机制来进行划分,可以分为3部分:源码注解,编译时注解,运行时注解。
源码注解:只在源码.java文件中存在,编译成.class字节码文件就不存在了;
编译时注解:在源码.java文件和字节码.class文件中都存在;
运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解。(spring框架中的@Autowired依赖注入的这种注解,它实现的就是在程序运行的过程当中自动的将外部传入的信息加载进去,它就是一种可以影响程序运行逻辑的运行时注解。)
按照来源来分
注解按照来源来进行划分,可以分为3部分:JDK注解,第三方注解,自定义注解。
还有一种元注解,它是对注解进行注解的。
不行了,写着写着字数又超了,快4000字了,面向对象最后一个特性:多态,我还没说呢,下次吧,今天得滚去运动了。。。感谢你的赏阅。
JAVA知识总结(三):继承和访问修饰符的更多相关文章
- java:包、继承,访问修饰符
包 包(package) 用于管理程序中的类,主要用于解决类的同名问题.包可以看出目录. 包的作用 [1] 防止命名冲突. [2] 允许类组成一个单元(模块),便于管理和维护 [3] 更好的保护类.属 ...
- C#继承机制 继承与访问修饰符
继承与访问修饰符 访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性.类的继承中有四个访问修饰符: public protected internal private.使用这些访问修饰符可指定 ...
- Java继承和访问修饰符
继承 概念:为了提取两个类中公共代码,可以使用继承抽取重复性的代码到一个公共类中,这个公共的类称为父类(super class).继承于父类的类称为子类(sub class). 关键字 ext ...
- java的访问控制(包、访问修饰符、修饰符)
一. java的类包 编写好一个源程序后,首先要执行javac命令进行编译源文件,并生成与源文件同名后缀为“.class”的字节码文件(类文件),该类文件与源文件默认在同一个目录中.该类文件是 ...
- Java知多少(19)访问修饰符(访问控制符)
Java 通过修饰符来控制类.属性和方法的访问权限和其他功能,通常放在语句的最前端.例如: 1 public class className { 2 // body of class 3 } 4 pr ...
- package,继承,访问修饰符
1.package 包(package),用于管理程序中的类,可用于处理类的同名问题. 1.1定义package的方法 package 包名; package用于定义包,必须写在源文件有效代码的第一句 ...
- 简单的描述Java中的构造函数,及访问修饰符
作为一个Java 初学者,对Java的理解可能有些片面,甚至有些错误的理解,对于观看此处的您,希望您选择性观看!!! 访问修饰符: 1.常用访问修饰符: public 共有的 private 私有的 ...
- java——关于数组的定义 和 访问修饰符的修饰内容
public class Shuzu { public static void main(String[] args) { // 定义数组 必须初始化长度,没有初始化要放数据 int[] in = { ...
- java入门概念个人理解之访问修饰符
类.方法.成员变量和局部变量的对应修饰符是否可以使用 修饰符 类 成员访求 构造方法 成员变量 局部变量 abstract(抽象的) √ √ - - - static (静态的) - √ - √ ...
随机推荐
- Springboot系列(七) 集成接口文档swagger,使用,测试
Springboot 配置接口文档swagger 往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配 ...
- python干货-类属性和方法,类的方法重写
类属性与方法 类的私有属性 __private_attrs: 两个下划线开头,表明为私有,外部不可用,内部使用时self.__private_attrs. 类的方法 在类的内部,使用 def 关键字来 ...
- Key Set HDU - 5363
这个题目套公式 2^(n-1)-1,再来个快速幂基本上就可以AC了 写这个题目的: 公式容易推到错: 容易写成 2^n-1/2...这样写出来结果也不错 但是一直哇 AC: #include< ...
- 再接再厉,JSONViewer现已支持Firefox、Microsoft Edge、360浏览器,可能是最好用的JSON格式化工具
之前写的JSONViewer,截至目前在谷歌商店里已经有1000+的自然下载量了 为什么开发JSONViewer? 日常开发中,拿到接口输出的JSON一般会去在线的JSON格式化网站查看,但是在线格式 ...
- HTML+CSS教程(一)简介及其基本标签的使用方法
一.前端 HTML(结构):HyPer TEXT Markup LanguageCSS(样式): 样式就是对于结构的一种美化JavaScript(js: 行为/ 提供了用户和界面的交互方式)jQuer ...
- 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...
- MySQL基础知识和常用命令总结
说明:以下内容是阅读书籍<<MySQL必知必会>>的摘要和总结 检索数据 排序检索数据 过滤数据 使用通配符过滤 使用正则表达式进行搜索 创建计算字段 使用数据处理函数 汇总数 ...
- phpcms 用phpexcel导入导出excel
html <form method="post" action="?m=content&c=content&a=public_add_excel&q ...
- Linux C语言 检测文件是否存在
头文件 unistd.h ) { // file exists } else { // file doesn't exist } You can also use R_OK, W_OK, and X_ ...
- How to check if directory exist using C++ and winAPI
如果看文件夹是否存在,必须看返回值是不是 INVALID_FILE_ATTRIBUTES #include <windows.h> #include <string> bool ...