韩顺平Java(持续更新中)

更新时间:2023-07-12 23:07:15 阅读: 评论:0

韩顺平Java(持续更新中)
原创上课笔记,转载请注明出处
第⼀章⾯向对象编程(中级部分) PDF为主
1.1 IDEA
删除当前⾏,ctrl+y
复制当前⾏,ctrl+d
补全代码,alt+/
添加或者取消注释,ctrl+/
导⼊该⾏需要的类,alt+enter
快速格式化代码,ctrl+ALT+L
快速运⾏程序,alt+r(⾃⼰设置)
⽣成构造器等,alt+inrt
查看⼀个类的层级关系,ctrl+H,继承有⽤(光标放在类名上)
快速定位某个⽅法的位置,ctrl+B(ctrl+⿏标点击)
⾃动分配变量,main⽅法中,.var,例如new Scanner(System.in).var
查看快捷键模板:Live Templates (例如,fori)
1.2 Object类详解(equals、==、hashCode等)
所有类都实现了Object类,都能使⽤Object类的⽅法。
1.2.1 ==运算符
基本类型—>判断值是否相等
引⽤类型—>判断地址是否相等
指向同⼀个地址,结果为true
1.2.2 equals()⽅法
1.2.2.1 基本介绍
Object的equals()⼀⽬了然,==运算符,⽤来判断地址是否相等
⽽String等类的equals()被重写了,⽤来判断内容是否相等(根据需求,判断内容相等的标准也是可能会有所改变的)
如何重写equals⽅法:
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 20, '男');
System.out.println(person1.equals(person2));//假,如果没有重写Person类的equals⽅法,这⾥的equals⽅法调⽤的Object的(即,判断的是地址)⽰例代码:
//重写Object 的 equals⽅法
public boolean equals(Object obj) {
//判断如果⽐较的两个对象是同⼀个对象,则直接返回true
if(this == obj) {
return true;
}
//类型判断
if(obj instanceof  Person) {//是Person,我们才⽐较
//进⾏向下转型, 因为我需要得到obj的各个属性
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age && der == p.gender;
}
//如果不是Person ,则直接返回fal
return fal;
}
1.2.2.2 课堂练习
第三个输出:因为Person并没有重写equals,所以这⾥调⽤的equals⽅法是Object的,判断地址是否相同的,⽽这两个新的对象肯定不相等,所以返回fal 这道题需要注意的是,基本数据类型的==运算符是判断内容的
1.2.3 hashCode()⽅法
1.2.4 toString()⽅法
全类名:包名+类名
/**Object的toString() 源码
(1)getClass().getName() 类的全类名(包名+类名 )
(HexString(hashCode()) 将对象的hashCode值转成16进制字符串
*/
public String toString() {
return getClass().getName() + "@" + HexString(hashCode());
}
1.2.5 finalize()⽅法
public class Finalize_ {
public static void main(String[] args) {
Car bmw = new Car("宝马");
//这时 car对象就是⼀个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调⽤该对象的finalize⽅法
//,程序员就可以在 finalize中,写⾃⼰的业务逻辑代码(⽐如释放资源:数据库连接,或者打开⽂件..)
//,如果程序员不重写 finalize,那么就会调⽤ Object类的 finalize, 即默认处理
//,如果程序员重写了finalize, 就可以实现⾃⼰的逻辑
bmw = null;
<();//主动调⽤垃圾回收器
System.out.println("程序退出了....");
}
}
class Car {
private String name;
//属性, 资源。。
public Car(String name) {
this.name = name;
}
//重写finalize
@Override
protected void finalize() throws Throwable {
System.out.println("我们销毁汽车" + name );
System.out.println("释放了某些资源...");
}
}
1.3 ⾯向对象的三⼤特征(封装、继承、多态)
⾯向对象的三⼤特征:封装、继承、多态。
1.3.1 封装
好处:隐藏实现的细节、可以对数据进⾏验证
实现的步骤:
封装与构造器:
/有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;禁毒素材
//我们可以将 t ⽅法写在构造器中,这样仍然可以验证
tName(name);
tAge(age);
tSalary(salary);
}
1.3.2 继承
提升代码的复⽤性、便于代码维护和扩展
注意:⼦类构造器内部有个默认隐藏的super()⽅法,调⽤⽗类的构造器。(⼦类构造器中不显⽰super指明⽗类构造器的话,就是默认调⽤⽗类⽆参构造器)。
当定义了⼀个有参构造器且没有显式定义⽆参构造器的话,那么默认的⽆参构造器就会被有参构造器覆盖。⼦类此时必须在所有构造器中⽤super指明调⽤的哪个⽗类构造器。super在普通⽅法也能⽤,调⽤⽗类对应的⽅法
这个细节⼀定要注意
从当前类往上⼀直追溯到Object类,然后从Object类⼀直调⽤构造器⽅法到当前类
继承的本质分析(重要):
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();//内存的布局
//?-> 这时请⼤家注意,要按照查找关系来返回信息(就近原则,⾃⼰没有就找⽗亲,⽗亲没有就找爷爷)
//(1) ⾸先看⼦类是否有该属性
//(2) 如果⼦类有这个属性,并且可以访问,则返回信息
//(3) 如果⼦类没有这个属性,就看⽗类有没有这个属性(如果⽗类有该属性,并且可以访问,就返回信息..)
//(4) 如果⽗类没有就按照(3)的规则,继续找上级⽗类,直到高效执行
System.out.println(son.name);//返回就是⼤头⼉⼦
//System.out.println(son.age);//返回的就是39
//System.out.Age());//返回的就是39
System.out.println(son.hobby);//返回的就是旅游
}
}
class GrandPa { //爷类
String name = "⼤头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {//⽗类
String name = "⼤头爸爸";
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //⼦类
String name = "⼤头⼉⼦";
}
注意⼀点:当打印son.age的时候,此时Son类没有age这个属性,于是去Father中寻找,但是这个age是私有的,此时编译器就会报错,若要访问,就要调⽤getAge()⽅法。(如果Father类中也没有age,就去GranPa中寻找)
此外,在现在这个代码情况下,想要访问GrandPa中的age属性(假设爷爷类中有age这个属性),需要在爷爷中创建⼀个不重名的get⽅法,并调⽤。
课堂练习:
这个题需要提醒⼀下,this会调⽤B的构造器,this(“abc")会调⽤B的有参构造器,⽽且this调⽤构造器,会有super(),如果再写⼀个super就冲突(这也是为什么super和this 不能共存,指访问构造器)。
注意执⾏顺序,往上找super
1.3.3 super关键字
super使⽤细节:
public class B extends A {
public int n1 = 888;
//编写测试⽅法
public void test() {
//super的访问不限于直接⽗类,如果爷爷类和本类中有同名的成员,也可以使⽤super去访问爷爷类
的成员;
// 如果多个基类(上级类)中都有同名的成员,使⽤super访问遵循就近原则。A->B->C
System.out.println("super.n1=" + super.n1);
super.cal();
}
//访问⽗类的属性 , 但不能访问⽗类的private属性 [案例]super.属性名
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3 );
}
public void cal() {
System.out.println("B类的cal() ⽅法...");
}
public void sum() {
System.out.println("B类的sum()");
//希望调⽤⽗类-A 的cal⽅法
//这时,因为⼦类B没有cal⽅法,因此我可以使⽤下⾯三种⽅式
社保基数计算器//找cal⽅法时(cal() 和 this.cal()),顺序是:
// (1)先找本类,如果有,则调⽤
// (2)如果没有,则找⽗类(如果有,并可以调⽤,则调⽤)
// (3)如果⽗类没有,则继续找⽗类的⽗类,整个规则,就是⼀样的,直到 Object类
// 提⽰:如果查找⽅法的过程中,找到了,但是不能访问(⽐如私有⽅法),则报错, cannot access
//      如果查找⽅法的过程中,没有找到,则提⽰⽅法不存在
/
/cal();
this.cal(); //等价 cal
//找cal⽅法(super.call()) 的顺序是直接查找⽗类,其他的规则⼀样
//super.cal();
//演⽰访问属性的规则
//n1 和 this.n1 查找的规则是
//(1) 先找本类,如果有,则调⽤
//(2) 如果没有,则找⽗类(如果有,并可以调⽤,则调⽤)
//(3) 如果⽗类没有,则继续找⽗类的⽗类,整个规则,就是⼀样的,直到 Object类
// 提⽰:如果查找属性的过程中,找到了,但是不能访问,则报错, cannot access
//      如果查找属性的过程中,没有找到,则提⽰属性不存在
System.out.println(n1);
System.out.println(this.n1);
//找n1 (super.n1) 的顺序是直接查找⽗类属性,其他的规则⼀样
System.out.println(super.n1);
}
//访问⽗类的⽅法,不能访问⽗类的private⽅法 super.⽅法名(参数列表);
public void ok() {
//st400();//不能访问⽗类private⽅法
}
//访问⽗类的构造器(这点前⾯⽤过):super(参数列表);只能放在构造器的第⼀句,只能出现⼀句!
public  B() {
伤感的语录
//super();
//super("jack", 10);
当然了英语super("jack");
}
}
super和this的⽐较:
1.3.4 重写/覆盖
重写(override)与重载(overload)的⽐较:
1.3.5 多态*
1.3.5.1 引出问题
待解决的问题:当对象不同时,需要调⽤的⽅法不⼀样,如果没有多态的话,我们可能就会根据不同对象的种类数重载同⼀个⽅法很多次,这样代码的复⽤性不⾼,不利于代码维护。
1.3.5.2 基本介绍
多态的具体体现:⽅法的多态和对象的多态
因为编译类型的对象可以重新指向其他的运⾏类型,所以运⾏类型可以改变。运⾏类型是Java实际执⾏时的类型,编译类型是编译器识别的。
P308 ⼀段代码的⽐较,使⽤了多态前后:animal是dog、cat的⽗类
//使⽤多态机制,可以统⼀的管理主⼈喂⾷的问题
//animal 编译类型是Animal,可以指向(接收) Animal⼦类的对象
//food 编译类型是Food ,可以指向(接收) Food⼦类的对象
public void feed(Animal animal, Food food) {
System.out.println("主⼈ " + name + " 给 " + Name() + " 吃 " + Name());
}
//主⼈给⼩狗喂⾷⾻头
//    public void feed(Dog dog, Bone bone) {
//        System.out.println("主⼈ " + name + " 给 " + Name() + " 吃 " + Name());
//    }
//    //主⼈给⼩猫喂黄花鱼
次开头的成语
//    public void feed(Cat cat, Fish fish) {
//        System.out.println("主⼈ " + name + " 给 " + Name() + " 吃 " + Name());
//    }
/
/如果动物很多,⾷物很多
//===> feed ⽅法很多,不利于管理和维护
//Pig --> Rice
//Tiger ---> meat ...
//...
向上转型:(转型向上还是向下,针对的是等号=右边的类型,相对于它是向上转⽗类,还是向下转⼦类)
⽗类的引⽤指向了⼦类的对象
羊字//向上转型: ⽗类的引⽤指向了⼦类的对象
//语法:⽗类类型引⽤名 = new ⼦类类型();
Animal animal = new Cat();
Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的⽗类
//向上转型调⽤⽅法的规则如下:
//(1)可以调⽤⽗类中的所有成员(需遵守访问权限)
//(2)但是不能调⽤⼦类的特有的成员
//(#)因为在编译阶段,能调⽤哪些成员,是由编译类型来决定的
//animal.catchMou();错误
//(4)最终运⾏效果看⼦类(运⾏类型)的具体实现, 即调⽤⽅法时,按照从⼦类(运⾏类型)开始查找⽅法
//,然后调⽤,规则我前⾯我们讲的⽅法调⽤规则⼀致。
animal.eat();//猫吃鱼..
animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡
向下转型:
//⽼师希望,可以调⽤Cat的 catchMou⽅法
//多态的向下转型
//(1)语法:⼦类类型引⽤名 =(⼦类类型)⽗类引⽤;
//问⼀个问题? cat 的编译类型 Cat,运⾏类型是 Cat
Cat cat = (Cat) animal;
cat.catchMou();//猫抓⽼⿏
//(2)要求⽗类的引⽤必须指向的是当前⽬标类型的对象
Dog dog = (Dog) animal; //可以吗?
System.out.println("ok~~");
1.3.5.3 多态的细节
属性重写问题
属性的调⽤是看编译类型,⽽⽅法是看运⾏类型
属性没有重写之说!属性的值看编译类型
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Ba ba = new Sub();//向上转型
System.out.unt);// ?看编译类型 10
Sub sub = new Sub();
System.out.unt);//?  20
}
}
class Ba { //⽗类
int count = 10;//属性
}
class Sub extends Ba {//⼦类
int count = 20;//属性
}
这⾥的判断对象类型是编译类型还是运⾏类型?运⾏类型
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof  BB);// true
System.out.println(bb instanceof  AA);// true
//aa 编译类型 AA, 运⾏类型是BB
//BB是AA⼦类
AA aa = new BB();
System.out.println(aa instanceof AA);// true
System.out.println(aa instanceof BB);// true,两个true说明是判断的运⾏类型
Object obj = new Object();
System.out.println(obj instanceof AA);//fal
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //⽗类
class BB extends AA {}//⼦类
1.3.5.4 多态课堂练习
这⼀题主要注意:属性看编译类型,⽅法看运⾏类型
1.3.5.5 动态绑定机制*
⼀个经典案例:第⼀句打印的a.sum()⽅法⾥⾯getI()是⼦类的还是⽗类的?
⾸先,根据⽅法的动态绑定机制,a的运⾏类型是B类,所以先去B类中找有没有sum⽅法,没有去A类中找,找到后发现getI⽅法,因为a的运⾏类型是B类,所以⼜先去B类中找getI⽅法,由于属性是没有动态绑定机制的,所以getI⽅法中的i就是B类中的i=20。
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运⾏类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 20
}
}
class A {//⽗类
public int i = 10;
//动态绑定机制:
public int sum() {//⽗类sum()
return getI() + 10;//20 + 10
}
public int sum1() {//⽗类sum1()
return i + 10;//10 + 10
}
public int getI() {//⽗类getI
return i;
}
}
class B extends A {//⼦类
public int i = 20;
//    public int sum() {
//        return i + 20;
//    }
public int getI() {//⼦类getI()
return i;
}
//    public int sum1() {
//        return i + 10;
//    }
}
1.3.5.6 多态数组
public class PloyArray {
public static void main(String[] args) {
//======================================================
//应⽤实例:现有⼀个继承结构如下:要求创建1个Person对象、
// 2个Student 对象和2个Teacher对象, 统⼀放在数组中,并调⽤每个对象say⽅法
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("mary", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scott", 30, 20000);
persons[4] = new Teacher("king", 50, 25000);
浙江理工大学是211还是985//循环遍历多态数组,调⽤say
for (int i = 0; i < persons.length; i++) {
//⽼师提⽰: person[i] 编译类型是 Person ,运⾏类型是是根据实际情况有JVM来判断
System.out.println(persons[i].say());//动态绑定机制,数组多态
//===================================================
//应⽤实例:如何调⽤⼦类特有的⽅法
//这⾥⼤家聪明. 使⽤类型判断 + 向下转型.
if(persons[i]  instanceof  Student) {//判断person[i] 的运⾏类型是不是Student
Student student = (Student)persons[i];//向下转型
student.study();
/
/⼩伙伴也可以使⽤⼀条语句 ((Student)persons[i]).study();
} el if(persons[i] instanceof  Teacher) {
Teacher teacher = (Teacher)persons[i];
} el if(persons[i] instanceof  Person){
//System.out.println("你的类型有误, 请⾃⼰检查...");
} el {
System.out.println("你的类型有误, 请⾃⼰检查...");
}
}
}
}
1.3.5.7 多态参数
第⼆章反射专题
2.1 ⼀个需求引出反射(快速⼊门)
需求:从⼀个配置⽂件中读取指定信息,并⽤这个信息创建对象且调⽤⽅法。
然后在实际操作中会发现,如下图,当获取到类的路径时,并不能通过直接new classfullpath() 来⽣成对象,因为classfullpath是⼀个String字符串!
类似于这样的需求在学习框架时很多,即通过外部⽂件配置,在不修改源码情况下,通过修改外部⽂件配置来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩展修改功能)这⼀点,在⽼韩的例⼦中,只需要把properties配置⽂件中的methodname更改即可
使⽤反射解决:通过classfullpath路径名,来获取到对应的类(有点反射的意思了)
在Java核⼼技术第11版中,获取对象实例的⽅法变成:
Object o = Constructor().newInstance();  // Object o = wInstance();
2.2 反射机制
反射原理图:
Java反射机制可以完成:
反射相关的主要类:
反射的优缺点:
优点:可以动态地创建和使⽤对象(也是框架底层核⼼),使⽤灵活,没有反射机制的话,框架技术就失去了底层⽀撑。
缺点:使⽤反射基本是解释执⾏,对执⾏速度会有影响。
// 传统⽅案
static void test1() {
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i = 0; i < 90000000; i++) {
<();
}
long end = System.currentTimeMillis();
System.out.println("传统⽅法调⽤耗时:"+ (end - start));
}
// 反射机制
static void test2() throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cls = Class.forName("Cat");
Object o = Constructor().newInstance();
Method method = Method("cry");
long start = System.currentTimeMillis();
for (int i = 0; i < 90000000; i++) {
method.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射⽅法调⽤耗时:" + (end - start));
}
输出:
传统⽅法调⽤耗时:6
反射⽅法调⽤耗时:501
对反射调⽤的优化⽅案——关闭访问检查
// 反射调⽤优化
static void test3() throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cls = Class.forName("Cat");
Object o = Constructor().newInstance();
Method method = Method("cry");
method.tAccessible(true);  // 在反射调⽤⽅法时,取消安全检查,进⾏速度优化
long start = System.currentTimeMillis();
for (int i = 0; i < 90000000; i++) {
method.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射优化后调⽤耗时:" + (end - start));
}

本文发布于:2023-07-12 23:07:15,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1093304.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:类型   属性   对象   访问
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图