深入类和对象
大家好呀!我是小笙!前几天被培训班的老师考察基础,发现漏洞还是有很多的,我想进一步学习java基础,所以我跟着韩老师学Java,以下是我的笔记
IDEA开发工具的简单分布介绍
包
本质就是文件夹 类的本质就是文件 package关键字
作用: 1.区分相同名字的类 2.可以很好的管理类 3.控制方法范围通过访问修饰符
包的规则和规范
包的命名规则:只能包含数组,字母,下划线,小圆点,但不能用数组开头,不能是关键字或者保留字
包的命名规范:全名都是小写字母 + 小圆点
比如 : com.公司名.项目名.业务模块名
常用包
*指的是包下所有的类都导入
细节注意
-
package的作用是声明当前类所在的包,需要放在类的最上面(意思就是package上面除了注释什么都不能放) ,一个类最多只有一句package
-
import关键字放在package下面,在类定义前面,可以有多句,没有顺序要求
// 一个类中最多只有一个package package com.al_tair.study; // import关键字放在package下面,在类定义前面,可以有多句,没有顺序要求 import java.util.Scanner; import java.util.Arrays; // 类定义 public class study{ public static void main(String[]args){} }
访问修饰符
访问修饰符的种类
- public : 对全部包中的类开放
- protected : 对不同包的子类和同一个包中的类公开
- 默认访问修饰符(无修饰符):对同一个包中的类(包含子类)公开,但是对不同包的子类不公开
- private : 只有类本身可以访问
使用注意细节
- 修饰符可以用来修饰类中的属性,成员方法以及类
- 只能用默认的和public来修饰类
面向对象编程的三大特征
封装, 继承,多态
封装
概念:就是把抽象的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只能通过被授权的操作【方法】,才能对数据进行操作
好处: 1.隐藏实现的细节 2.可以对数据进行验证,保证数据安全合理
封装的实现步骤
继承
extends 关键字
格式:class 子类 extends 父类 { }
好处:解决代码复用性,当多个类中有相同的属性和方法时候,我们可以抽出相同属性和方法作为父类
注意细节
-
子类继承了父类所有的属性和方法,但是私有属性和方法不能被直接访问,子类和父类之间必须满足 is - a 的逻辑关系
-
子类必须调用父类的构造器,完成父类的初始化,默认无参父类构造器,当父类没有无参构造器并且子类未用super指明对应的父类的构造器,编译不会通过
// 父类 public class person { public person() { System.out.println("父类构造器"); } } // 子类 public class Child extends person{ public Child() { // 默认 super(); System.out.println("子类构造器"); } } class test{ public static void main(String[] args) { Child child = new Child(); } } // 运行结果 父类构造器 子类构造器
-
super and this 关键字使用的时候必须放在构造器的第一行,因此这两个方法调用不能共存在一个构造器
-
java所有类都是Object类的子类
-
父类的构造器的调用不仅限于直接父类,会一直追朔直到Object类(*父类)
-
子类最多只能继承一个父类(单继承机制)
内存分布图
查找属性和方法数据根据就近原则
详解super关键字
用处:super 代表父类的引用,用于访问父类的方法,属性和构造器
注意细节:
- 无法访问父类的私有方法和属性
- 使用的时候必须放在构造器的第一行,因此只能调用一次父类的构造器
- 当子类的属性,方法和父类重名时,为了访问父类的成员,必须通过super关键字来完成
this 和 super 的区别
多态
概念:方法或者对象具有多种状态,多态是建立在封装和继承之上的
方法的重载和重写体现了方法的多态
对象的多态具体体现
-
前提条件:两个对象(类)存在继承关系
-
一个对象的编译类型和运行类型可以不一致
// Animal 父类 Dog 子类 Cat 子类 Animal animal = new Dog(); // 编译类型 Aniaml 运行类型 Dog animal = new Cat(); // 运行类型是可以改变的
-
编译类型在定义对象时候就确定了
-
运行类型是可以改变的
-
编译类型看定义,运行类型看 new 对象
细节分析
-
多态的向上转型
- 本质:父类的引用指向子类的对象
- 语法:父类类型 引用名 = new 子类类型();
- 特点:编译类型看定义,运行类型看 new 对象
- 用该对象调用方法的时候,只能调用父类中的方法,不能调用子类特有的方法,因为编译不通过;但是调用方法在运行类型中是先从子类开始查找方法
- 属性没有重写的说法,所以属性的值看编译类型
-
多态的向下转型
-
语法:子类类型 引用名 = (子类类型)父类引用;
-
只能强转父类的引用,不能强转父类的对象
-
可以调用子类类型中的所有成员
-
我的理解:就是让编译和运行类型上进行一个统一
// 举例 Animal animal = new Dog(); // 编译类型 Aniaml 运行类型 Dog Dog dog = (Dog) animal; // // 编译类型 Dog 运行类型 Dog
-
动态绑定机制
具体体现:
- 当调用对象方法时候,该方法会和该对象的内存地址/ 运行类型进行动态绑定
- 当调用对象的属性的时候没有动态绑定的说法
举例说明:
// 举例
public class demo{
public static void main(String[] args){
father f = new son();
System.out.println(f.sum()); // 40
System.out.println(f.sum2()); // 60
}
}
class father{ // 父类
public int attribute = 10;
public int sum(){
return getAttribute() + 10; // getAttribute()绑定的是子类的该方法
}
public int sum2(){
return attribute + 50; // 属性没有动态绑定机制
}
public int getAttribute(){
return attribute;
}
}
class son extends father{ // 子类
public int attribute = 30;
public int getAttribute(){
return attribute;
}
}
Object类详解
equals
equals方法 和 == 比较运算符 的区别
== :如果判断基本数据类型,判断值是否相同;如果判断引用数据类型,判断的是地址是否相同(是否是 同一个对象)
equals:是Object类中的方法,只能用来判断引用类型,默认是判断地址是否相同,但是像String类重写了该方法,用来判断字符串值是否相同
// Object类的源码
public boolean equals(Object obj) {
return (this == obj);
}
// String类的源码
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*/
public boolean equals(Object anObject) {
if (this == anObject) { // 比较地址是否相同
return true;
}
if (anObject instanceof String) { // 判断是否为String 或者 String的父类
String aString = (String)anObject; // 向下转型:目的是为了获得String类的属性和方法
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
}
// StringLatin1类的源码 底层就是比较字符数组中每个字符是否相同
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
hashCode
作用:返回该对象的哈希码值,是为了提高哈希表的性能
注意细节
- 提高具有哈希结构的容器的效率
- 两个引用都指向同一个对象,则哈希值一定相同
- 哈希值主要是根据地址来的,将对象的内部地址转换成一个整数来实现的
toString
默认返回:全类名 + @ + 哈希值十六进制
作用:用于返回该对象的属性信息
// Object源码
// java.lang.Object@16b98e56
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
注意细节
-
当直接输出一个对象时,toString方法会被默认的调用
Object o = new Object(); System.out.println(o.toString()); // java.lang.Object@16b98e56 System.out.println(o); //java.lang.Object@16b98e56
finalize
概念:当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器调用此方法
注意细节
-
当某个对象没有任何引用时,则jvm虚拟机就会来销毁该对象,在销毁该对象前,就会调用该对象的finalize方法
public class person { public person() {} // 该方法已经被废除,不推荐使用 @Override protected void finalize() throws Throwable { System.out.println("我已经被销毁了..."); } } class test{ public static void main(String[] args) { new person(); System.gc(); // 运行垃圾回收器 } } // 显示效果:我已经被销毁了...
-
垃圾回收机制的调用,由系统来决定,我们可以通过System.gc() 主动触发垃圾回收机制
断点调试
断点调试(idea)默认快捷键
- F7:跳入方法
- F8:逐行执行代码
- shift+F8:跳出方法
- F9:执行到下一个断点
Idea debug如何进入 Jdk源码
解决方法1
使用force step into : 快捷键 alt + shift + F7
解决方法2
这个配置一下就好了:
点击Setting --> Build,Execution,Deployment --> Debugger --> Stepping
把Do not step into the classes中的java.*,javax.*取消勾选
相关面试题
1.请说明一下final, finally, finalize的区别
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源
回收,例如关闭文件等。
2.请说明面向对象的特征有哪些方面
- 抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只
是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 - 继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派
生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生
类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 - 封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一
系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 - 多态性:多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享
、代码共享的优势,很好的解决了应用程序函数同名问题。
3.请说明Java是否支持多继承
Java中类不支持多继承,只支持单继承(即一个类只有一个父类)。 但是java中的接口支持多继承,,即一个子接口可以有多个父接口。(接口的作用是用来扩展对象的功能,一个子接口继承多个父接口,说明子接口扩展了多个功能,当类实现接口时,类就扩展了相应的功能)