Java面向对象高阶
继承
继承是java面向对象编程技术的基石,因为它允许创建分等级层次的类
继承就是子类继承父类的特征和行为,使得子类对象具有父类的属性(特征)和方法(行为)。
子类实例化内存分析
super不是引用类型的变量,super中存储的不是内存地址,super指向的不是父类对象 super代表的是当前子类对象中的父类型特征
当调用super()时,虽然调用了父类的构造方法,但是并不会创建父类的对象!因为构造方法的作用是为堆区中的对象的属性初始化,不是创建对象。
super()/this()的调用只能放在构造方法的第一行(且只能出现一次),因此this()和super()不能同时调用(this会调用super)
Java之super关键字(华为云):
https://www.huaweicloud.com/articles/5ea8fc2a9b558621f58c3dd64bec09a0.html
在子类对象中,子类想访问父类的方法或者属性(有权限),使用“super.访问。
注意:若子类重写了父类的方法,但子类要调用父类的被重写方法,可使用super.调用。当子类中有父类一样的属性/方法,调用父类的该属性或者方法super.不可省略。
重写
重写发生在运行期,是子类对父类的允许访问的方法的实现过程重新编写
- 返回值类型,参数列表,方法名必须与被重写方法完全相同,访问权限大于等于父类,抛出异常小于等于父类
- 若父类方法访问修饰符为private/static/final子类无法重写该方法,但是被static/private修饰的方法可以被再次声明
重载与重写的区别
方法的重载和重写都是实现多态的方式,前者是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表则为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更高访问权限,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有要求,无法依据返回类型区分。
final
final是一个修饰符也是一个关键字。
- 被final修饰的类无法被继承
- 被final修饰的变量,如果是基本数据类型的变量,则数值一旦在初始化之后便不能更改。如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是它指向的对象内容是可变的
- 被final修饰的方法无法被重写,但可以重载
注意:类的private方法会隐式地被指定为final方法。
final修饰变量的初始化时机:显示初始化/构造器初始化(只会被赋值一次,因此二选一,默认赋值编译失败)
浅谈java中"static","final"的用法
https://www.huaweicloud.com/articles/f10c570487e346164153e8b1eb94d4a1.html
抽象类
抽象类必须使用abstract class声明 一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。
格式: abstract class 类名{ // 抽象类 }
抽象方法
只声明而未实现的方法称为抽象方法(未实现指的是:没有“{}”方法体),抽象方法必须使用abstract关键字声明。 格式:
abstract class 类名{ // 抽象类 public abstract void 方法名() ; // 抽象方法,只声明而未实现
}
抽象类不能被实例化
- 抽象类不能直接实例化,即:不能直接使用关键字new完成。
- 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须重写抽象类中的全部抽象方法。
抽象类有构造方法(虽然无法被实例化),子类对象实例化与普通类的继承是一样的,都是要先调用父类中的构造方法(默认无参),之后再调用子类自己的构造方法。
抽象类和普通类的区别
- 抽象类必须用public或protected修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。 默认缺省为 public
- 抽象类不可以使用new关键字创建对象
- 如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么子类也必须定义为 abstract类
- 抽象类不能使用final声明 ,因为final属性修饰的类是不能有子类的 , 而抽象类必须被子类继承
接口
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口。 定义格式:
interface 接口名称{全局常量 ;抽象方法 ;
}
这种思想是接口是定义(规范,约束)与实现(名实分离的原则)的分离。
优点: 1、 降低程序的耦合性 2、 易于程序的扩展 3、 有利于程序的维护
全局常量和抽象方法的简写
因为接口本身都是由全局常量和抽象方法组成 , 所以接口中的成员定义可以简写:
- 全局常量编写时, 可以省略public static final 关键字,例如: public static final String INFO = "内容" ; 简写后: String INFO = "内容" ;
- 抽象方法编写时, 可以省略 public abstract 关键字, 例如: public abstract void print() ; 简写后: void print() ;
如果一个类即要实现接口,又要继承抽象类的话,则按照以下的格式编写:
class 子类 extends 父类 implements 父接口1,父接口2...{
}
接口的继承
接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承
interface C extends A,B{
}
如果一个接口要想使用,必须依靠子类。 子类(若非抽象类)要实现接口中的所有抽象方法
接口和抽象类的区别
1. 接口默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象方法。
2. 接口中除了 全局常量,不能有其他变量,而抽象类没有要求。
3. 接口方法默认修饰符是 public,抽象方法可以有 public、protected 和 default 修饰 (抽象方法就是为了被重写所以不能用 private 关键字修饰)。
4. ⼀个类可以实现多个接口,但只能继承⼀个抽象类。接口可以通过 extends 关键字继承多个接口。
5. 在设计层面的角度,抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(方法)(行为)进行抽象。抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种辐射式规范。
- 在 jdk 7 前,接口只能有全局常量和抽象方法。这些接口方法必须由选择实现接口的类实现。
- jdk8 的时候接口可以有默认方法和静态方法功能。
- Jdk 9 在接口中引入私有方法和私有静态方法。
新特性 https://blog.csdn.net/tracydragonlxy/article/details/78082600
多态
对象的多态性,在类中有子类和父类之分,子类就是父类的一种形态 ,对象多态性就从此而来。
它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译不确定,在程序运行期间才确定,即⼀个引用变量会指向哪个类的实例对象,该引用变量调用的是哪个类中实现的方法,必须由程序运行期间才确定。
分类
- 编译时多态(又称静态多态)
- 运行时多态(又称动态多态)
重载(overload)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行的时候调用的是 确定的方法。 一般说的多态是运行时多态也就是编译时不确定调用哪个具体方法,直到运行时才能确定。
实现多态有 3 个必要条件:
- 继承类/实现接口
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,这样该引用才既能可以调用父类的方 法,又能调用子类的方法(同方法调用子类重写方法)。
Person a=null;
Student b=new Student();
a=b;
a.show();
总结:父类引用指向子类对象,因为子类继承了父类,重写父类方法,所以 能够表现出来多种状态的形式
对象的类型转换
- 向上转型:将子类实例变为父类实例 |- 格式:父类 父类对象 = 子类实例 ;
- 向下转型:将父类实例变为子类实例 |- 格式:子类 子类对象 = (子类)父类实例 ;
public class Person {public void say() {}public static void name(Person p) {p.say();}public static void main(String[] args) {Student student = new Student();Staff staff=new Staff();name(student);name(staff);}}
class Student extends Person{public void say() {System.out.println("student");}
}
class Staff extends Person{public void say() {System.out.println("staff");}
}
Person person=new Person();Student student2=(Student) person;//运行时报如下错误//Exception in thread "main" java.lang.ClassCastException: class inheritence.Person cannot be cast to class inheritence.Student (inheritence.Person and inheritence.Student are in unnamed module of loader 'app')Person person2=new Student();Student student3=(Student) person2;//合法
以上实例是一个常见的错误,父类引用可以被其自身及其子类实例的地址值赋值,但是如果该引用赋值为自身实例的地址值,将其向下转型为子类引用时运行时(编译可以通过)会报异常。只有父类引用赋值为其子类实例的地址,向下转型为兼容的子类引用时才能顺利运行。
instanceof
- 作用: 判断某个对象是否是指定类的实例
- 格式: 实例化对象 instanceof 类 //此操作返回boolean类型的数据
public static void name(Person p) {if (p instanceof Student) {p.say();System.out.println("p is student");}if (p instanceof Staff) {p.say();System.out.println("p is staff");}}
Object类(概述)
Object类是所有类的父类,如果一个类没有明确的继承某一个具体的类,则将默认继承Object类。
Object的多态:使用Object可以接收任意的引用数据类型
toString: 返回对象的内存地址,建议重写Object中的toString方法。 此方法的作用:返回对象的字符串表示形式。
equals
作用:指示某个其他对象是否“等于”此对象。建议重写Object中的equals(Object obj)方法
经典面试题:=和equals的区别
= : 判断两个对象在内存里的存储位置是否一样。(基本数据类型 比较的是值,引用数据类型比较的是内存地址)。
equals:
- 没有重写equals()则通过 equals() 比较该类的两个对象时,等价于通过 =比较这两个对象的地值。
- 重写 equals() (建议,相当于定制相等的规则)若它们的内容相等,则返回 true 也就是这两个对象相等。
public boolean equals(Object obj) {return (this == obj); }
String,File,Date等类都重写的equals方法,对于两个String对象来说,值相等说明它们包含相同的字符序列,对基本类型的包装类来说,值相等说明对应的基本类型的值相等。
String aa = "haha"; // 放在常量池中String bb = "haha"; // 从常量池中查找 String a = new String("haha"); // a 为⼀个String类型引⽤String b = new String("haha"); // b为另⼀个String类型引⽤,内容⼀样if (aa == bb) // trueif (a == b) // false,不是同⼀对象if (a.equals(b)) // trueif (2 ==2.0) // true
@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (age != other.age)return false;return true;}
内部类(不常用)
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
分类:
- 成员内部类
- 局部内部类 (包含匿名内部类)
- 静态内部类
成员内部类
class Outer {private int a = 0;public Outer(int x) {this.a = x;}class Inner { //内部类public void say() {System.out.println("hello");}}
}
成员内部类作为类的成员变量可以访问外部类的所有成员属性和成员方法(含private成员和静态成员)。
注意:当成员内部类拥有和外部类同名的成员变量或者方法时,会覆盖之,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以该形式进行访问: 外部类.this.成员变量 外部类.this.成员方法
外部使用成员内部类
Outer o=new Outer();
Outer.Inner i=o.new Inner();
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。只能访问final型的局部变量.适用于类只使用一次的情况,比如监听器的自定义实现。
public People getPerson(){class Student extends People{ //局部内部类int age =0;}return new Student();
}
只能访问final型的局部变量的内存层面理解:
public Person() {this.age = 0;int number=0;class A{public void show() {System.out.println(number);} }number++;//编译失败new A().show();}
每一个class都会被单独编译为一个字节码文件,包括内部类,也就是说作为一个独立的个体它无法访局部变量number,因此编译器就会对int类型的局部变量做一个备份,在jdk 1.8前,局部内部类访问的局部变量前需要被final显式修饰否则编译失败,之后编译器默认给局部变量添加final关键字修饰,因此无法改变其值。
匿名内部类
interface A{void say();}A a=new A() {@Overridepublic void say() {// TODO Auto-generated method stub }};
使用匿名内部类必须要继承一个父类或者实现一个接口(仅能只继承一个父类或者实现一个接口)同时它也没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的隐式引用
注意:
- 匿名内部类中不能定义构造函数。
- 匿名内部类中不能存在静态成员变量和静态方法。
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
- 匿名内部类不能是抽象的,必须要实现继承的类或者实现的接口的所有抽象方法。
- 只能访问final型的局部变量
静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。 静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员 变量或者方法.
静态内部类的实例化:Outter.Inner inner = new Outter.Inner();
包装类
在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就不符合于这种设计思想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型 的包装类。
包装类型可以是 null,但基本类型不行。这使包装类型可以应用于 POJO 中,而基本类型不行。因为数据库的查询结果可能是 null,若使用基本类型,会因为自动拆箱(将包装类型转为基本类型)会抛出空指针异常。
包装类型可用于泛型,而基本类型不可以(编译失败)因为泛型在编译时会进行类型擦除,最后只保留原始类型(只能是 Object 类及其子类,不包括基本类型)
但是基本类型比包装类型更高效。基本类型在栈中直接存储数值,而包装类型则存储的是堆中 的引用。比起基本类型而言,包装类型需要占用更多的内存空间。
以上的八种包装类分为两种大类型:
- Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
- Object:Character、Boolean都是Object的直接子类。
装箱和拆箱操作
- 将一个基本数据类型变为包装类称为装箱操作。
- 将一个包装类变为一个基本数据类型称为拆箱操作。
因为所有的数值型的包装类都是Number的子类,Number的类中定义了如下的操作方法,以下的全部方法都是进行拆箱的操作
在JDK1.5,Java新增了自动装箱和自动拆箱,而且可以直接通过包装类进行四则运算和自增自建操作。例如:
- Float f = 10.3f ; // 自动装箱
- float x = f ; // 自动拆箱
- System.out.println(f * f) ; // 直接利用包装类完成
字符串转换
可以将一个字符串变为指定的基本数据类型,此点一般在接收输入数据上使用 较多。
- 在Integer类中提供了以下的操作方法: public static int parseInt(String s) :将String变为int型数据
- 在Float类中提供了以下的操作方法: public static float parseFloat(String s) :将String变为Float
- 在Boolean 类中提供了以下操作方法: public static boolean parseBoolean(String s) :将String变为boolean
- ......................
可变参数
一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,在JDK 1.5之后提供了新的功能,可以根 据需要自动传入任意个数的参数。
语法: 返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意: 可变参数只能出现在参数列表的最后。
public void test(int a ,int...nums) {System.out.println("a is "+a);for (int i = 0; i < nums.length; i++) {System.out.println(nums[i]); }}
递归概述
递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或者间接调用自身方 法的算法。
public static int test2(int num) {if(num==1) {return 1;}else {return num*test2(num-1);}}
假如传入的参数为5,则f(5)返回5f(4),f(4)返回4f(3)....最后返回f(1)返回1,2f(1)即为f(2)=2,从而得到f(3),f(4),f(5) 返回1之前是递的过程,之后是归的过程。
Java面向对象高阶相关推荐
- java监听器高阶运用_史上最全面'java监听器'解读,读完就能用进项目 | 程序员灯塔...
一.Web监听器 什么是web监听器? web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特定事件,比如ServletContext,HttpSession,ServletR ...
- Java基础学习笔记(三)_Java核心技术(高阶)
本篇文章的学习资源来自Java学习视频教程:Java核心技术(高阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...
- 由Java实际编程中,从西洋油画与中国写意山水画,联想到低阶Java编程与高阶java编程...
A.本文名词解释 低阶Java编程==Java1.x时代:按照内部Java版本号,1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6. 高阶Java编程==Java2.x时代:猜测幻想 ...
- Kotlin 使用高阶函数实现回调
lambda 和 高阶函数 之前学习了 lambda 和高阶函数,然后在 android 开发中对 onClick 事件进行监听是一个很常用的功能,kotlin 的常规实现如下: rootView.s ...
- 高阶Day1:面向对象,面向过程,类和对象的属性和方法创建
高阶Day1:面向对象,面向过程,类和对象的属性和方法创建 高级编程学习4个内容: 面向对象 MySQL数据库 网络编程 并发编程 面向过程(POP)与面向对象(OOP): 类和对象: 类名的定义: ...
- 高阶函数||编程范式: 命令式编程/声明式编程 || 编程范式: 面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)
编程范式: 命令式编程/声明式编程 编程范式: 面向对象编程(第一公民:对象)/函数式编程(第一公民:函数) 高阶函数 filter/map/reduce filter中的回调函数有一个要求: 必须返 ...
- Java高阶代码_Java高阶语法---Volatile
背景:听说Volatile Java高阶语法亦是挺进BAT的必经之路. Volatile: volatile同步机制又涉及Java内存模型中的可见性.原子性和有序性,恶补基础一波. 可见性: 可见性简 ...
- Java高阶语法---final
背景:听说final Java高阶语法是挺进BAT必经之路. final: final关键字顾名思义就是最终不可改变的. 1.含义:final可以声明成员变量.方法.类和本地变量:一旦将引用声明为fi ...
- JavaScript 面向对象编程(三) —— 函数进阶 / 严格模式 / 高阶函数 / 闭包 / 浅拷贝和深拷贝
本篇为 JavaScript 进阶 ES6 系列笔记第三篇,将陆续更新后续内容.参考:JavaScript 进阶面向对象 ES6 :ECMAScript 6 入门 系列笔记: JavaScript 面 ...
最新文章
- 更改exe程序图标_更改电脑文件夹颜色、样式、图标,让文件夹不再是单一的黄色...
- 按钮传值给ajax,用jquery和ajax实现分页时,按钮怎么给jquery传值?
- web元件库/axure元件库/常用web组件/常用表单/导航栏/边框/图标/日期时间选择器/评分组件/穿梭框/输入框/步骤条/
- postgresql 使用pg_restore时显示role root does not exist的解决办法
- 2-设置文件类型扩展名
- zynq开发系列2:GPIO连接MIO控制LED闪烁(SDK端代码编写详解)
- 6.4 随机森林实战
- 【bzoj1999】[Noip2007]Core树网的核 树的直径+双指针法+单调队列
- Linux添加浮动路由,Linux路由配置详情
- 1解锁方式9008_黔隆科技刷机教程红米4A忘记密码刷机解锁降级救砖解屏幕锁账户锁教程...
- windows系统安全
- 《STL》— NYOJ STL练习 习题汇总
- 编写jQuery插件的方法
- 5. 等可能概型(古典概型)
- PHP简单的手机验证码验证过程
- 戴尔服务器虚拟 介质,使用Dell R710 IDRAC挂载虚拟介质
- 【安卓笔记】自定义toggleButton
- Ethereum Architecture : 以太坊架构
- 输入法/非输入法切换 无法取消快捷键问题 以及 shift按键关闭CapsLock问题
- 黄冈师范学院教育管理的论文选题
热门文章
- httpd.exe: Syntax error on line 40 of */apache/conf/httpd.conf: ServerRoot must be a valid directory
- iOS开发者的“祖师爷”去世了:他发明了Objective-C语言
- 中国各省人力资本测算就业人员受教育程度构成(2000-2021年)
- Android UI系列 - 布局 - 属性详解
- H3C IRF2典型应用
- SVG滤镜+阴影+渐变--学习笔记
- VMware虚拟机上LINUX系统的安装及其练习题
- Linux那些事儿 之 戏说USB(23)设备的生命线(二)
- 【Life系列】之关于工作和生活的思考与反思
- jquery使用淘宝接口跨域查询手机号码归属地实例