推广网站,wordpress文件夹介绍,上海网页制作与网站设计,qq网页版登陆Java学习第十二天——面向对象中级#xff1a;
IDEA#xff1a;
创建完新项目后#xff0c;再src里面创建.java文件进行编写。
src——存放源码文件#xff08;.java文件#xff09;#xff1b;out——存放编译后的字节码文件#xff08;.class文件#xff09;
在I…Java学习第十二天——面向对象中级
IDEA
创建完新项目后再src里面创建.java文件进行编写。
src——存放源码文件.java文件out——存放编译后的字节码文件.class文件
在IDEA中我们run一个文件时会先编译成一个class文件再运行。
常用快捷键
删除当前行ctrl y;复制当前行ctrl d;补全代码alt /添加注释和取消注释ctrl /第一次是注释后一次是取消注释导入改行需要的类先配置 auto import然后使用alt enter即可快速格式化代码ctrl alt L快速运行程序alt R快速生成构造器自定义为Alt I了Alt Insert选择Constructor要选择属性的话要按住ctrl查看类的层级关系学完类后很有用把光标放在要查找的类上然后ctrl H定位方法学完继承后很有用将光标放到一个方法上输入 ctrl B可以定位到方法自动分配变量名通过再后面跟.var 举例——new.Mytools().var还有其余很多的快捷键暂时不介绍。
模板template/自定义模板
file - settings - editor - Live templates - 查看有哪些模板快捷键/可以自己增加模板。
模板可以高效地完成开发。
不过建议新手暂时不用哦还是再熟悉熟悉代码。 包
为什么要有包
因为我们在一个文件夹下不能有两个同名文件。
三大作用
区分相同名字的类当类很多时可以很好地管理类控制访问范围
包的基本语法
package 包名;
class 类名{}package 为关键字表示打包下面的内容表示在这个包内的内容。
包的本质
其实就是创建不同的文件夹/目录来保存类文件。
在IDEA中我们找到src右键找到package点击输入包名便创建好了。
包名里的.表示第几级目录如com.xiaomingcom为xiaoming的上一级目录其内含有子目录xiaoming
包的命名
命名规则
只能包含数字、字母、下划线、小圆点.但不能用数字开头不能是关键字或保留字。
命名规范
一般是小写字母小圆点一般是
com.公司名.项目名.业务模块名。
常用的包
一个包下包含很多的类java中常用的包有
java.lang.*——lang是基本包默认引用不需要再引入java.util.*——util包系统提供的工具包工具类如Scannerjava.net.*——网络包网络开发java.awt.*——是做java的界面开发GUI。
如何引用包
有两种格式
import java.util.Scanner;这种格式就是只引入包下的一个特定的类import 包名.类名;import java.util.*; 这种格式表示将java.util包所有都引入。(import 包名. *)
package com.jiangxian.pkg;
import java.util.Arrays;
/*我们需要使用哪个类就引入哪个类就好了尽量不要使用*号导入。
*/public class Import01 {public static void main(String[] args) {// 使用系统提供的Arrays完成数组排序int[] arr {-1, 20, 2, 13, 3};// 比如对其进行排序// 传统方法是自己编写排序函数冒泡// 系统是提供了相关的类可以方便完成ArraysArrays.sort(arr);for(int i 0; i arr.length; i){System.out.println(arr[i] \t);}}
}
注意事项和使用细节
package的作用是声明当前类所在的包需要放再类class的最上面一个类中最多有一句packageimport指令 位置放置再package的下面在类定义的前面可以有多句且没有顺序要求。 访问修饰符
基本介绍
java提供四种访问控制修饰符号用于控制方法和属性成员变量的访问权限范围
公开级别用public修饰对外公开受保护级别用protected修饰对子类和同一个包中的类公开默认级别没有修饰符号向同一个包中的类公开私有级别用private修饰只有类本身可以访问不对外公开。6
访问级别访问修饰控制符同类同包子类不同包公开public√√√√受保护protected√√√×默认没有修饰符√√××私有private√×××
注意事项
修饰符可以用来修饰属性成员方法和类只有public和默认可以修饰类只有默认和public可以修饰类且遵循上表的访问权限特点暂时没有学习继承关于子类的访问权限在下文展开成员方法的访问规则和属性完全一致。 面向对象编程三大特征
基本介绍
封装继承多态。 封装Encapsulation——第一大特征
封装介绍
封装encapsulation就是把抽象出的数据属性和对数据的操作方法封装在一起数据被保护在内部程序的其它部分只有通过被授权的操作方法才能对数据进行操作。
封装的理解和好处
隐藏实现的细节可以对数据进行验证保证安全合理性。比如我们使用电脑但是我们可以不用去知道电脑是怎么运行的。
封装的实现步骤
属性私有化private提供一个public的set用于修改属性Alt I调出选择Setter提供一个public的get方法用于获取某个属性的值Alt I调出选择Getter
封装的快速入门
package com.jiangxian.encap;public class Encapsulational01 {public static void main(String[] args) {Person person new Person();person.setName(江弦);person.setAge(21);person.setSalary(30000);System.out.println(person.info());System.out.println(person.getSalary());// 使用构造器Person person2 new Person(80,凤九,500000);System.out.println(凤九的信息);System.out.println(person2.info());}
}class Person{public String name;private int age;private double salary;public void say(int n, String name){}public Person(int age, String name, double salary) {this.age age;this.name name;this.salary salary;// 将set写入构造器内这样仍然可以验证。setAge(age);setSalary(salary);setName(name);}public Person() {}public String getName() {return name;}public void setName(String name) {if(name.length() 2 name.length() 6){this.name name;}else{this.name 无名人;System.out.println(名字的长度不对请输入(2-6)个字符的名字。);}}public int getAge() {return age;}public void setAge(int age) {if(age 0 age 150){this.age age;}else{this.age 0;System.out.println(你设置的年龄不正确。);}}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary salary;}public String info(){return 信息为 name name , age age , salary salary;}
}
封装与构造器
24.11.6
可以将封装与构造器结合为什么要这样做呢因为我们想要在构造器中也引入防控机制如上文中 public Person(int age, String name, double salary) {//this.age age;//this.name name;//this.salary salary;// 将set写入构造器内这样仍然可以验证。setAge(age);setSalary(salary);setName(name);}练习
package com.jiangxian.encap;public class Account {private String name;private double balance;private String password;public Account(String name, double balance, String password) {setName(name);setBalance(balance);setPassword(password);}public Account() {}public String getName() {return name;}public void setName(String name) {if(name.length() 2 name.length() 4) {this.name name;}else{this.name 无名人;System.out.println(请输入2~4个字符的名字。);}}public double getBalance() {return balance;}public void setBalance(double balance) {if(balance 20){this.balance balance;}else{this.balance 0;System.out.println(余额必须大于20。);}}public String getPassword() {return password;}public void setPassword(String password) {if(password.length() 6){this.password password;}else{this.password 000000;// soutSystem.out.println(密码长度有误你的默认密码是000000);}}public String info(){return name name , balance balance , password password;}
}
package com.jiangxian.encap;public class AccountTest {public static void main(String[] args) {Account account new Account(jiangxian, 100, 123456);System.out.println(account.info());System.out.println(江弦的账户);Account jiangxian new Account(江弦, 3080, 123456);System.out.println(jiangxian.info());}
} 继承Extends——第二大特征
为什么需要继承
从一个例子引入
package com.jiangxian.extend_;
// 小学生 -》 模拟小学生考试的情况
public class Pupil {public String name;public int age;private double score;public void setName(String name) {this.name name;}public void testing(){System.out.println(小学生 name 正在考小学数学。);}public void info(){System.out.println(小学生名 name 年龄 age 成绩 score);}
}
package com.jiangxian.extend_;
// 大学生 -》 模拟大学生的考试情况
public class Graduate {public String name;public int age;private double score;public void setName(String name) {this.name name;}public void testing(){System.out.println(大学生 name 正在考大学数学。);}public void info(){ // 和小学生不一样的地方System.out.println(大学生名 name 年龄 age 成绩 score);}
}package com.jiangxian.extend_;public class Extends01 {public static void main(String[] args) {Pupil pupil new Pupil();pupil.name XiaoMing;pupil.age 10;pupil.setScore(60);pupil.testing();pupil.info();System.out.println();Graduate graduate new Graduate();graduate.name DaMing;graduate.age 22;graduate.testing();graduate.setScore(100);graduate.info();}
}
我们发现两个类的属性与方法有很多都是相同的我们可以使用继承去解决我们的代码复用问题。
基本介绍
继承可以解决代码复用当多个类存在相同的属性变量和方法时可以从这些类中抽象出父类在父类中定义这些相同的属性和方法所有的子类不需要重新定义这些属性和方法只需要通过extends来声明继承父类即可。
基本语法
class 子类 extends 父类{}子类就会自动拥有父类定义的属性和方法父类叫做超类基类共有属性和共有方法子类又叫派生类特有属性和特有方法。
快速入门
package com.jiangxian.extend_.improve_;
// 父类是Pupil和Graduate的父类
public class Student {// 共有的属性与方法如下所示public String name;public int age;private double score;public void setScore(double score) {this.score score;}public void info(){System.out.println(学生名 name 年龄 age 成绩 score);}
}
package com.jiangxian.extend_.improve_;public class Pupil extends Student{public void testing(){System.out.println(小学生正在考小学数学..);}
}
package com.jiangxian.extend_.improve_;public class Graduate extends Student {public void testing(){System.out.println(大学生正在考大学数学..);}
}
package com.jiangxian.extend_.improve_;public class Test {public static void main(String[] args) {Pupil pupil new Pupil();pupil.name XiaoMing;pupil.age 10;pupil.setScore(60);pupil.testing();pupil.info();System.out.println();Graduate graduate new Graduate();graduate.name DaMing;graduate.age 22;graduate.testing();graduate.setScore(100);graduate.info();}
}
继承带来的便利
代码的复用性提高了代码的扩展性和维护性提高了。
继承的细节 子类继承了所有的属性和方法非私有的属性和方法可以在子类直接访问但是私有属性和方法不能在子类直接访问可以间接访问要通过父类提供的公共的方法 package com.jiangxian.extend_;public class Base { // 父类// 四个不同修饰类型的四个属性public int n1 100;protected int n2 200;int n3 300;private int n4 400;// 无参构造器public Base(){System.out.println(base()....);}// 四个不同修饰符的方法public void test100(){System.out.println(test100()....);}protected void test200(){System.out.println(test200()....);}void test300(){System.out.println(test300()....);}private void test400(){System.out.println(test400()....);}// 父类提供一个public的方法public int getN4() {return n4;}public void callTest400(){test400();}
} package com.jiangxian.extend_;public class Sub extends Base{public Sub(){System.out.println(sub()...);}public void sayOk(){// 非私有的属性可以在子类直接访问System.out.println(n1 n2 n3 getN4());// System.out.println(n4);test100();test200();test300();// test400callTest400();}
} package com.jiangxian.extend_;public class ExtendsDetail {public static void main(String[] args) {Sub sub new Sub();sub.sayOk();}
} 子类必须调用父类的构造器完成父类的初始化。 当创建子类对象时不管使用子类的哪个构造器默认情况下总会去调用父类的无参构造器如果父类没有提供无参构造器则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作否则编译会不通过。第一个代码演示有默认构造器的情况剩下两个代码演示没有默认构造器的情况 public class Sub extends Base{public Sub(){// 这里隐藏了一句super();这样就会默认调用系统的无参构造器System.out.println(sub()...);}public Sub(String name){System.out.println(sub(String name)...);}public void sayOk(){// 非私有的属性可以在子类直接访问System.out.println(n1 n2 n3 getN4());// System.out.println(n4);test100();test200();test300();// test400callTest400();}
}// 父类没有提供无参构造器
package com.jiangxian.extend_;public class Base { // 父类// 四个不同修饰类型的四个属性public int n1 100;protected int n2 200;int n3 300;private int n4 400;// 无参构造器
// public Base(){
// System.out.println(base()....);
// }public Base(String name, int age){System.out.println(base(String, int age)....);}// 四个不同修饰符的方法public void test100(){System.out.println(test100()....);}protected void test200(){System.out.println(test200()....);}void test300(){System.out.println(test300()....);}private void test400(){System.out.println(test400()....);}// 父类提供一个public的方法public int getN4() {return n4;}public void callTest400(){test400();}
} package com.jiangxian.extend_;public class Sub extends Base{public Sub(){// 这里隐藏了一句super();这样就会默认调用系统的无参构造器super(Smith, 10);System.out.println(sub()...);}public Sub(String name){super(Tom, 100);System.out.println(sub(String name)...);}public void sayOk(){// 非私有的属性可以在子类直接访问System.out.println(n1 n2 n3 getN4());// System.out.println(n4);test100();test200();test300();// test400callTest400();}
} 若希望指定去调用父类的某个构造器则显示的调用一下super(参数列表) package com.jiangxian.extend_;public class Sub extends Base{public Sub(String name, int age){// 1. 调用父类的无参构造器如下或者什么都不写就会默认调用super()// super();// 父类的无参构造器// 2.调用父类的Base(String name)// super(江弦);// 3.调用父类的Base(String name, int age)super(name, age);System.out.println(Sub(String name, int age)...);}public Sub(){// 这里隐藏了一句super();这样就会默认调用系统的无参构造器super(Smith, 10);System.out.println(sub()...);}public Sub(String name){super(Tom, 100);System.out.println(sub(String name)...);}public void sayOk(){// 非私有的属性可以在子类直接访问System.out.println(n1 n2 n3 getN4());// System.out.println(n4);test100();test200();test300();// test400callTest400();}
} super在使用时需要放在子类构造器的第一行super关键字只能在构造器中使用先有爸爸才能有儿子 super()和this()this()是调用同类中的其它构造器的意思都只能放在构造器的第一行且这两个方法不能共存一个构造器 java所有类都是Object类的子类 父类构造器的调用不限于直接父类将一直往上追溯到Object类顶级父类 子类最多只能继承一个父类指直接继承即java中是单继承机制想要A继承B和C只能是B继承C然后A再继承B 不能滥用继承子类和父类之间必须满足is-a的逻辑关系Person is a Music。
继承的本质
294/910
当子类对象创建好后建立查找关系。
super关键字
super代表父类的引用用于访问父类的属性、方法、构造器。
基本语法
访问父类的属性但不能访问父类的private属性super.属性名;访问父类的方法不能访问父类的private方法super.方法(参数列表);访问父类的构造器super(参数列表);只能放在构造器的第一句只能出现一句。
super给编程带来的便利/细节
调用父类的构造器的好处分工明确父类属性由父类初始化子类的属性由子类初始化当子类中有和父类的成员属性和方法重名时为了访问父类的成员必须通过super。若没有重名使用super、this、直接访问时一样的效果super访问不限于直接父类若爷爷类和本类中有同名的成员也可以使用super去访问爷爷类的成员若多个基类中都有重名的成员使用super访问就近原则。
super和this的比较
No.区别点superthis1访问属性从父类开始查找属性访问本类的属性如果本类没有此属性则从父类中继续查找2调用方法从父类开始查找方法访问本类中的方法如果本类没有此方法则从父类继续查找3调用构造器调用父类构造器必须放在子类构造器的首行调用本类构造器必须放在构造器的首行4特殊子类访问父类的对象表示当前对象
例子
package com.jiangxian.super_;public class Base {public int n1 999;public int age 111;public void cal(){System.out.println(Base类的cal()...);}public void eat(){System.out.println(Base类的eat()...);}
}
package com.jiangxian.super_;public class A extends Base{// 4个属性public int n1 100;protected int n2 200;int n3 300;private int n4 400;public A(){}public A(String name){}public A(String name, int age){}// public void cal(){
// System.out.println(A类的cal()...);
// }public void test100(){}protected void test200(){}void test300(){}private void test400(){}
}
package com.jiangxian.super_;public class B extends A{public int n1 888;// 编写测试方法public void test(){// super的访问不限于直接父类若爷爷类和本类中有同名的成员也可以使用super去访问爷爷类的成员// 若多个基类上级类中都有同名的成员使用super访问就近原则。System.out.println(super.n1 super.n1);super.cal();}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类// 提示若查找方法的过程中找到了但不能访问private则报错cannot access// 若查找方法的过程中没有找到则提示方法不存在。// cal();this.cal();// 找cal方法(super.cal())的顺序是直接查找父类其他的规则一样// super.cal()// 演示访问属性的规则// 和方法一样。System.out.println(n1);System.out.println(this.n1);// 查找父类的System.out.println(super.n1);}public void ok(){super.test100();super.test200();super.test300();// super.test400(); 不能直接访问父类的private方法}public B(){super(jack);}
}
package com.jiangxian.super_;public class Super01 {public static void main(String[] args) {B b new B();b.test();}
} 方法重写/覆盖override
基本介绍
方法重写就是子类有一个方法和父类的某个方法的名称、返回类型、参数都一样那么我们就说子类的这个方法覆盖了父类的方法。
快速入门
package com.jiangxian.override_;public class Animal {public void cry(){System.out.println(动物叫唤...);}
}
package com.jiangxian.override_;public class Dog extends Animal{// 1.Dog是Animal子类// 2.Dog的cry方法和Animal类的cry定义形式一样名称、返回类型、参数// 3.这时我们就说Dog的cry方法重写了Animal的cry方法public void cry(){System.out.println(小狗在叫...);}
}
package com.jiangxian.override_;public class Override01 {public static void main(String[] args) {Dog dog new Dog();dog.cry();}
}
注意事项和使用细节
需要满足以下条件
子类的方法的参数方法名称要和父类方法的参数方法名称完全一样子类方法的返回类型和父类方法返回类型一样或者是父类发返回类型的子类例如父类 返回类型是Object子类方法返回类型是String public Object getInfo();父类public String getInfo();子类 子类方法不能缩小父类方法的访问权限。 void sayOk();public void sayOk();
package com.jiangxian.override_;public class Animal {public void cry(){System.out.println(动物叫唤...);}public Object m1(){return null;}public String m2(){return null;}public AAA m3(){return null;}protected void eat(){}
}
package com.jiangxian.override_;public class Dog extends Animal{// 1.Dog是Animal子类// 2.Dog的cry方法和Animal类的cry定义形式一样名称、返回类型、参数// 3.这时我们就说Dog的cry方法重写了Animal的cry方法public void cry(){System.out.println(小狗在叫...);}// 细节子类方法的返回类型和父类方法返回类型一样// 或者是父类返回类型的子类。public String m1(){ //构成重写因为String是Object的子类return null;}// 报错提示一个不兼容的返回类型
// public Object m2(){
// return null;
// }public BBB m3(){return null;}public void eat(){}// protected void eat(){}
}
class AAA{
}class BBB extends AAA {}package com.jiangxian.override_;public class Override01 {public static void main(String[] args) {Dog dog new Dog();dog.cry();}
}
和重载的区别
名称发生范围方法名形参列表返回类型修饰符重载overload本类必须一样至少有一个不同无要求无要求重写override父子类必须一样全部相同子类重写的方法返回类型和父类一致或者是父类返回类型的子类。子类方法不能缩小父类方法的访问范围。 多态polymorphic——第三大特征难点
考虑一个喂食问题假设有一个动物园里面每只动物都需要喂食且喂食的东西种类都不一样虽然都是喂食但实际喂食的东西不一样。
我们可以使用重载函数的方式去完成但是不利于我们维护和管理当动物很多的时候。
package com.jiangxian.poly_;public class Food {private String name;public Food(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}
package com.jiangxian.poly_;public class Master {private String name;public Master(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}// 主任给小狗喂食public void feed(Dog dog, Bone bone){System.out.println(主人 name 给 dog.getName() 吃 bone.getName());}// 主人给小猫喂食public void feed(Cat cat, Fish fish){System.out.println(主人 name 给 cat.getName() 吃 fish.getName());}
}
package com.jiangxian.poly_;public class Animal {private String name;public Animal(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}
package com.jiangxian.poly_;public class Cat extends Animal{public Cat(String name) {super(name);}
}
package com.jiangxian.poly_;public class Dog extends Animal{public Dog(String name) {super(name);}
}
package com.jiangxian.poly_;public class Fish extends Food{public Fish(String name) {super(name);}
}
package com.jiangxian.poly_;public class Bone extends Food{public Bone(String name) {super(name);}
}
为了解决代码的复用性不高且不利于代码维护我们引入了多态的概念。
多态的基本介绍
方法或对象具有多种形态是面向对象的第三大特征多态是建立再封装和继承的基础上的。
多态的具体体现 方法的多态重写和重载体现多态 对象的多态核心困难重点 一个对象的编译类型和运行类型可以不一致编译类型在定义对象时就确定了不能改变运行类型是可以变化的编译类型看定义时 号左边运行类型看 右边Animal animal new Dog(); animal的编译类型时Animal运行类型是Doganimal new Cat();animal的运行类型现在变为了Cat编译类型任然是Animal package com.jiangxian.poly_.objpoly_;public class Animal {public void cry(){System.out.println(Animal is crying...);}
} package com.jiangxian.poly_.objpoly_;public class Dog extends Animal{Override // 注解public void cry() {System.out.println(Dog is crying...);}
} package com.jiangxian.poly_.objpoly_;public class Cat extends Animal{Overridepublic void cry() {System.out.println(cat is crying...);}
} package com.jiangxian.poly_.objpoly_;public class PolyObject {public static void main(String[] args) {// animal 的编译类型是 Animal运行类型 AnimalAnimal animal new Animal();animal.cry(); // 执行到这行时animal的运行类型是Animal运行Animal的cry// animal1 的编译类型是 Animal运行类型是DogAnimal animal1 new Dog();animal1.cry();// 执行到这行时animal1的运行类型是Dog运行Dog的cryAnimal animal2 new Cat();animal2.cry();// 编译类型仍然是 Animal但现在的运行类型为 Doganimal new Dog();animal.cry();// 执行Dog的cry}
} 父类的对象引用可以指向子类对象运行时以运行类型为主。 披着羊皮的狼羊——编译类型狼——运行类型
快速入门
现在我们来更改之前的代码
package com.jiangxian.poly_;public class Master {private String name;public Master(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}// 使用多态机制// animal 的编译类型是Animal可以接收指向Animal和Animal子类的对象// food 的编译类型是 Food可以接收指向Food 和 Food子类的对象public void feed(Animal animal, Food food){System.out.println(主人 name 给 animal.getName() 吃 food.getName());}// // 主任给小狗喂食
// public void feed(Dog dog, Bone bone){
// System.out.println(主人 name 给 dog.getName() 吃 bone.getName());
// }
// // 主人给小猫喂食
// public void feed(Cat cat, Fish fish){
// System.out.println(主人 name 给 cat.getName() 吃 fish.getName());
// }
}
多态的注意事项和细节讨论
多态的前提两个对象存在继承关系建立在继承和封装的基础上
多态的向上转型。
本质父类的引用指向了子类的对象语法父类类型 引用名 new 子类类型()特点编译类型看左边运行类型看右边。 可以调用父类中的所有成员需遵守访问权限无法使用private不能调用子类中特有成员因为在编译阶段能调用哪些成员由编译类型决定最终运行结果看子类的具体实现若子类没有就找父类和前面super的调用是一样的。
多态的向下转型 语法子类类型 引用名 子类类型 父类引用 只能强转父类的引用不能强转父类的对象 Animal animal new Cat(); // animal是父类的引用指向的确实是Cat类型的对象。
Cat cat (Cat) animal;要求父类的引用必须是指向当前目标类型的对象披着羊皮的狼是狼不会是老虎。 当向下转型后可以调用子类类型中所有的成员。
属性的重写问题
属性没有重写之说属性的值看编译类型。
instanceof 比较操作符用于判断对象的类型是否为XX类型或XX类型的子类型判断的是运行类型若是返回true否则为false。
动态绑定机制非常非常重要
当调用对象方法的时候该方法会和该对象的内存地址/运行类型绑定当调用对象属性时没有动态绑定机制哪里声明哪里使用。
package com.jiangxian.poly_.dynamic;public class A {public int i 10;public int sum(){return getI() 10;}public int sum1(){return i 10;}public int getI(){ // 父类有getIreturn i;}
}
package com.jiangxian.poly_.dynamic;public class B extends A{public int i 20;
// public int sum(){
// return i 20;
// }public int getI(){ // 子类也有getIreturn i;}public int sum1(){return i 10;}
}
package com.jiangxian.poly_.dynamic;public class DynamicBinding {public static void main(String[] args) {A a new B();System.out.println(a.sum()); // 发生动态绑定// 1.看a的运行类型是什么发现时B类型的所以调用子类的getI// 2.getI是返回属性没有动态绑定所以返回的是子类的i// 3.由于子类没有sum函数所以使用父类的答案为30System.out.println(a.sum1());}
}
看到函数时要注意有没有动态绑定机制。
多态的应用
1多态数组
数组的定义类型为父类类型里面保存的实际元素类型为子类类型。
package com.jiangxian.poly_.polyarr_;public class Person {private String name;private int age;public Person(String name, int age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}public String say(){return name \t age;}
}
package com.jiangxian.poly_.polyarr_;public class Student extends Person {private double score;public Student(String name, int age, double score) {super(name, age);this.score score;}public double getScore() {return score;}public void setScore(double score) {this.score score;}Overridepublic String say() {return 学生 super.say() 分数 score;}// 特有方法public void study(){System.out.println(学生 getName() 正在学Java。);}
}
package com.jiangxian.poly_.polyarr_;public class Teacher extends Person{private double salary;public Teacher(String name, int age, double salary) {super(name, age);this.salary salary;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary salary;}Overridepublic String say() {return 教师 super.say() 薪水: salary;}// 特有方法public void teach(){System.out.println(老师 getName() 正在学java课程。);}
}
package com.jiangxian.poly_.polyarr_;public class PolyArray {public static void main(String[] args) {Person[] persons new Person[5];persons[0] new Person(Jack, 20);persons[1] new Student(Marry, 18, 100);persons[2] new Student(Smith, 19, 31);persons[3] new Teacher(Scott, 30, 20000);persons[4] new Teacher(King, 50, 25000);for(int i 0; i persons.length; i){System.out.println(persons[i].say());if(persons[i] instanceof Student){((Student)persons[i]).study();}else if(persons[i] instanceof Teacher){((Teacher)persons[i]).teach();}else if(persons[i] instanceof Person){}else{System.out.println(你输入的类型有误。);}}}}
2多态参数
方法定义的形参类型为父类类型实参类型运行为子类类型。
例如前面说的喂动物。
下面给出一个另外的例子
package com.jiangxian.poly_.polyparameter_;public class Employee {private String name;private double salary;public Employee(String name, double salary) {this.name name;this.salary salary;}public String getName() {return name;}public double getSalary() {return salary;}public void setName(String name) {this.name name;}public void setSalary(double salary) {this.salary salary;}public double getAnnual(){return salary*12;}
}
package com.jiangxian.poly_.polyparameter_;public class Manage extends Employee {private double bonus;public Manage(String name, double salary, double bonus) {super(name, salary);this.bonus bonus;}public double getBonus() {return bonus;}public void setBonus(double bonus) {this.bonus bonus;}Overridepublic double getAnnual() {return super.getAnnual() bonus;}public void manage(){// 因为name是私有类型所以只能通过getName来访问System.out.println(经理 getName() is managing.);}
}
package com.jiangxian.poly_.polyparameter_;public class Worker extends Employee{public Worker(String name, double salary){super(name, salary);}public void work(){System.out.println(工人 getName() is working.);}
}
package com.jiangxian.poly_.polyparameter_;public class PolyParameter {public static void main(String[] args) {Worker tom new Worker(Tom, 2500);Manage milan new Manage(Milan, 5000, 200000);PolyParameter plogParameter new PolyParameter();plogParameter.showEmpAnnual(tom);plogParameter.showEmpAnnual(milan);plogParameter.testWork(tom);plogParameter.testWork(milan);}public void showEmpAnnual(Employee e){System.out.println(e.getAnnual());}public void testWork(Employee e){if(e instanceof Worker){((Worker)e).work();}else if(e instanceof Manage){((Manage)e).manage();}else{System.out.println(类型错误请自检。);}}
} Object类详解
Object是所有类的父类所以需要知道其内部有什么。
equals方法 和 equals的对比 是一个比较运算符
既可以判断基本类型也可以判断引用类型是否相等判断基本类型时判断的是值是否相等判断引用类型时判断地址是否相等即判断是不是同一个对象只关注运行类型不管编译类型。
package com.jiangxian.object_;public class Equals01 {public static void main(String[] args) {A a new A();A b a;A c new B();A d c;System.out.println(c d);System.out.println(b a);}
}class A{
}
class B extends A{
}
equals方法时Object类的一个方法 只能用于判断引用类型 默认判断的是地址是否相同子类中往往重写该方法用于判断内容是否相同。 public boolean equals(Object obj) { // Object中的equals原码return (this obj); // 使用 判断而用判断引用类型就是判断地址是否相同即是否是同一个对象}public boolean equals(Object obj) { // Integer中的equals原码if (obj instanceof Integer) { // 先判断obj是不是Integer的类型和子类型return value ((Integer)obj).intValue(); // 若是比较值的大小即可}return false; // 若不是Integer的类型或子类或者值不相等直接返回False}如何重写equals方法
package com.jiangxian.object_;public class Person {private String name;private int age;public Person(String name, int age) {setName(name);setAge(age);}public String getName() {return name;}public void setName(String name) {if(name.length() 2 name.length() 6){this.name name;}else{System.out.println(你输入的名字长度不合规默认为无名。);this.name 无名;}}public int getAge() {return age;}public void setAge(int age) {if(age 0 age 120){this.age age;}else{System.out.println(你的年龄不符合生物学默认为0岁);this.age 0;}}public boolean equals(Person obj){if(obj this){return true;}if(obj instanceof Person){Person person (Person)obj;return this.name.equals(person.getName()) this.age person.getAge();}return false;}
}
package com.jiangxian.object_;public class Equals02 {public static void main(String[] args) {Person p1 new Person(江弦, 21);Person p2 new Person(江弦, 21);System.out.println(p1 p2);System.out.println(p1.equals(p2));}
}
hashcode方法在第二阶段深入现在留个印象
返回对象的哈希码值。支持此方法是为了提高哈希表例如java.util.HashTable 提供的哈希表的性能。
提高具有哈希结构的容器的效率两个引用若指向同一个对象则哈希值肯定是一样的两个引用若指向的是不同的对象则哈希值肯定是不一样的哈希值主要是根据地址号来的不能完全将哈希值等价为地址以后在集合中若hashCode需要的话也可以进行重写。
package com.jiangxian.object_;public class HashCode_ {public static void main(String[] args) {AA aa new AA();AA aa1 new AA();AA aa2 aa;System.out.println(aa.hashCode(): aa.hashCode());System.out.println(aa1.hashCode(): aa1.hashCode());System.out.println(aa2.hashCode(): aa2.hashCode());}
}class AA{}
toString方法
基本介绍
默认返回全类名包名与类名 哈希值的十六进制子类往往重写toString方法用于返回对象的属性信息。 public String toString() {return getClass().getName() Integer.toHexString(hashCode());}package com.jiangxian.object_;public class ToString_ {/*原码1getClass().getName() 类的全类名包名 类名2Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串public String toString() {return getClass().getName() Integer.toHexString(hashCode());}*/public static void main(String[] args) {Monster monster new Monster(小妖怪, 巡山的, 1000);System.out.println(monster.toString() hashcode: monster.hashCode());}
}class Monster{private String name;private String job;private double sal;public Monster(String name, String job, double sal) {this.name name;this.job job;this.sal sal;}
}
重写
由于经常重写其也被集成到了快捷键Alt Insert我更改为了Alt I。
package com.jiangxian.object_;public class ToString_ {/*原码1getClass().getName() 类的全类名包名 类名2Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串public String toString() {return getClass().getName() Integer.toHexString(hashCode());}*/public static void main(String[] args) {Monster monster new Monster(小妖怪, 巡山的, 1000);System.out.println(monster.toString() hashcode: monster.hashCode());}
}class Monster{private String name;private String job;private double sal;public Monster(String name, String job, double sal) {this.name name;this.job job;this.sal sal;}// 重写toString方法输出对象的属性// 快捷键Alt Insert选择toString默认是返回对象的属性值。Overridepublic String toString() {return Monster{ name name \ , job job \ , sal sal };}
}
直接输出一个对象时toString方法会被默认的调用
package com.jiangxian.object_;public class ToString_ {/*原码1getClass().getName() 类的全类名包名 类名2Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串public String toString() {return getClass().getName() Integer.toHexString(hashCode());}*/public static void main(String[] args) {Monster monster new Monster(小妖怪, 巡山的, 1000);System.out.println(monster.toString() hashcode: monster.hashCode());System.out.println(monster);}
}class Monster{private String name;private String job;private double sal;public Monster(String name, String job, double sal) {this.name name;this.job job;this.sal sal;}// 重写toString方法输出对象的属性// 快捷键Alt Insert选择toString默认是返回对象的属性值。Overridepublic String toString() {return Monster{ name name \ , job job \ , sal sal };}
}
finalize方法
当对象被回收时系统自动调用该对象的finalize方法子类可以重写该方法做一些释放资源的操作比如对象打开了一个文件这就是占用了一个资源关闭文件就是释放资源什么时候被回收当某个对象没有任何引用时则jvm就认为这个对象是一个垃圾对象就会使用垃圾回收机制来销毁对象正在销毁对象前会先调用finalize方法垃圾回收机制的调用是由系统来决定也可以通过System.gc()主动出发垃圾回收机制。在新版中finalize已经被弃用了且在实际开发中不会使用所以就不细看了。
package com.jiangxian.object_;public class Finalize_ {public static void main(String[] args){Car bmw new Car(BMW); // 现在有一个对象引用bmw指向Car对象bmw null;// 现在将bmw指向 null 那么之前创建的Car对象就没有人使用了变为一个垃圾// 垃圾回收器就会进行销毁即把堆中Car的那个空间给释放出来了// 在销毁对象前会调用该对象的finalize方法我们可以在这个方法中写一些自己的业务逻辑代码比如释放资源数据库连接或者是打开的文件// 若程序员不重写finalize方法那么就会调用Object的finalize方法// 若程序员重写了finalize方法就能实现自己的业务逻辑了。System.gc();}
}class Car{private String name;public Car(String name){this.name name;}Overrideprotected void finalize() throws Throwable {System.out.println(销毁汽车 this.name);System.out.println(释放了某些资源。);}
}
如何查看原码
在IDEA中将光标放在想要查看原码的方法上点击ctrl b即可访问。
或者右键方法点击 Go To - Declaration or Usages 访问。 断点调试
为什么要有断点调试
断点调试能让我们一步步的看原码的执行过程从而发现错误所在
在断点调试的过程中是运行状态是以对象的运行类型来执行的。
断点调试介绍
断点调试是指在程序的某一行设置一个断点调试时程序运行到这一行就会停住该行此时没有执行然后你可以一步一步往下调试调试过程中可以看各个变量当前的值出错的话调试到出错的代码行即显示错误停下进而分析从而找到bug所在。是程序员必须掌握的技能断点调试也能帮助我们查看java底层源代码的执行过程提高程序员的Java水平。
断点调试的快捷键
F7跳入方法内F8逐行执行代码shift F8跳出方法F9执行到下一个断点。
断点调试应用
01
想在哪行加断点就将鼠标挪动到行号处单击鼠标即可。然后debug运行
package com.jiangxian.debug_;public class test01 {public static void main(String[] args) {int sum 0;for(int i 0; i 10; i){sum i;System.out.println(i i);System.out.println(sum sum);}System.out.println(end..);}
}
02
数组越界
package com.jiangxian.debug_;public class test02 {public static void main(String[] args) {int arr[] new int[5];for (int i 0; i arr.length; i) {System.out.println(arr[ i ] arr[i]);}}
}
03
进入JDK的方法源码需要先配置一下要是不想看就自己勾选回来吧~
点击Setting -- Build,Execution,Deployment -- Debugger -- Stepping把Do not step into the classes中的java.*javax.*取消勾选其他的随意。
但是进入源码可以会看晕那么怎么出来呢
可以使用shift F8 跳出一层重复直到跳回我们进入的位置。
package com.jiangxian.debug_;import java.util.Arrays;public class test03 {public static void main(String[] args) {int[] arr {1, -1, 10, -20, 100};// 这个例子是为了看源码Arrays.sort的实现Arrays.sort(arr);for(int i 0; i arr.length; i){System.out.println(arr[i]);}System.out.println(end..);}
}
04
演示如何执行到下一个断点
package com.jiangxian.debug_;import java.util.Arrays;public class test04 {public static void main(String[] args) {int[] arr {8, -1 , 199, 70, 10};Arrays.sort(arr);for (int i 0; i arr.length; i) {System.out.println(arr[i] \t);}System.out.println(hello100);// 断点System.out.println(hello200);System.out.println(hello300);System.out.println(hello400);System.out.println(hello500);System.out.println(hello600); // 断点System.out.println(end...);}}
05
查看对象的创建过程以及动态继承的实现
package com.jiangxian.debug_;public class DebugExercise {public static void main(String[] args) {// 创建对象的过程// 1.加载Person类// 2.1默认初始化2.显示初始化3.构造器初始化// 3.返回对象的地址Person person new Person(江弦,21);System.out.println(person);}
}class Person{private String name;private int age;public Person(){}public Person(String name, int age){this.name name;this.age age;}Overridepublic String toString() {return Person{ name name \ , age age };}
} 零钱通
模仿微信的零钱通
项目的开发流程
项目需求说明 使用Java开发 零钱通项目可以完成收益入账消费查看明细退出系统等功能。
先完成菜单并可以选择完成零钱通明细即内部的功能完成收益入账完成消费完成退出功能
项目开发说明
项目代码实现 先完成基本功能过程编程后改进为OOP。
面向过程的代码
package com.jiangxian.smallchange;
import java.text.SimpleDateFormat;
import java.util.Scanner;
import java.util.Date;public class SmallChangeSys {// 1.先完成显示菜单并可以选择菜单给出对应提示public static void main(String[] args) {// 定义一个循环条件变脸loopboolean loop true;// 为什么实现功能的选择我们需要定义一个Scanner与用户形成交互Scanner scanner new Scanner(System.in);String key ;// 2.实现明细1、使用数组2、适用对象3、使用String拼接// 为什么暂时这样定义就可以了呢因为我们还没有收益入账消费等后续只要把这两个的内容拼接到details的后面就可以了String details ---------------零钱通明细---------------;// 3.实现收益入账要完成这个程序驱动程序员增加新的变量和代码double money 0.0;double balance 0.0;Date date null; // date是java.util.Date 类型表示日期SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); // 可以用于日期格式化// 4.完成消费完成这个功能我们也需要增加一些变量String note ;// 让用户对是否退出做出判断char choice;do{// 为什么用do while循环因为菜单至少要显示一次System.out.println(\n零钱通菜单);System.out.println(\t\t\t1 零钱通明细);System.out.println(\t\t\t2 收益入账);System.out.println(\t\t\t3 消 费);System.out.println(\t\t\t4 退 出);System.out.println(请选择功能1-4);key scanner.next();// 使用分支控制switch(key){case 1:System.out.println(details);break;case 2:System.out.println(收益入账金额);money scanner.nextDouble();if (money 0){System.out.println(你输入的金额有误收益不应该为负数请仔细确认);break;}balance money;date new Date(); // 获取当前的日期格式很奇怪在循环前应该要设置下格式details details \n收益入账\t money \t sdf.format(date) \t balance;break;case 3:System.out.println(消费金额为);money scanner.nextDouble();// money 的值需要校验不能比余额大if (money balance){System.out.println(你输入的金额有误超过了你的剩余财产请检验);break;}System.out.println(输入消费说明);note scanner.next();date new Date();balance - money;details \n note \t- money \t sdf.format(date) \t balance;break;case 4:// 一段代码一般只完成一个小功能尽量不要混在一起这样阅读起来比较轻松。System.out.println(你确认要退出吗(y/n));choice scanner.next().charAt(0);while(choice ! y choice ! n){System.out.println(你的输入有误请输入yes或no或者y或n);choice scanner.next().charAt(0);}if(choice y){loop false;}break;default:System.out.println(你输入了零钱通没有的功能。);}}while(loop);System.out.println(你退出了零钱通。);}
}
OOP
package com.jiangxian.smallchange;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;/*** 该类是完成零钱通的各个功能的类* 使用OOP面向对象编程* 将各个功能对应一个方法。*/public class SmallChangeOOP {// 属性怎么来的就是我们面向过程里面设定的变量boolean loop true;Scanner scanner new Scanner(System.in);String key ;String details ---------------零钱通明细---------------;double money 0.0;double balance 0.0;Date date null; // date是java.util.Date 类型表示日期SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); // 可以用于日期格式化String note ;char choice;// 方法是怎么来的就是我们分析时候拆解的实现步骤// 先完成显示菜单并可以选择public void menu(){do{// 为什么用do while循环因为菜单至少要显示一次System.out.println(\n选择零钱通菜单(OOP));System.out.println(\t\t\t1 零钱通明细);System.out.println(\t\t\t2 收益入账);System.out.println(\t\t\t3 消 费);System.out.println(\t\t\t4 退 出);System.out.println(请选择功能1-4);key scanner.next();// 使用分支控制switch(key){case 1:this.detail();break;case 2:this.income();break;case 3:this.consume();break;case 4:// 一段代码一般只完成一个小功能尽量不要混在一起这样阅读起来比较轻松。this.exit();break;default:System.out.println(你输入了零钱通没有的功能。);}}while(loop);System.out.println(你退出了零钱通。);}// 再完成零钱通明细public void detail(){System.out.println(details);}// 完成收入public void income(){System.out.println(收益入账金额);money scanner.nextDouble();if (money 0){System.out.println(你输入的金额有误收益不应该为负数请仔细确认);// break; 在方法里应该是return即退出方法不再执行return;}balance money;date new Date(); // 获取当前的日期格式很奇怪在循环前应该要设置下格式details details \n收益入账\t money \t sdf.format(date) \t balance;}// 完成消费public void consume(){System.out.println(消费金额为);money scanner.nextDouble();// money 的值需要校验不能比余额大if (money balance){System.out.println(你输入的金额有误超过了你的剩余财产请检验);return;}System.out.println(输入消费说明);note scanner.next();date new Date();balance - money;details \n note \t- money \t sdf.format(date) \t balance;}// 完成退出public void exit(){System.out.println(你确认要退出吗(y/n));choice scanner.next().charAt(0);while(choice ! y choice ! n){System.out.println(你的输入有误请输入yes或no或者y或n);choice scanner.next().charAt(0);}if(choice y){loop false;}}
}
package com.jiangxian.smallchange;public class SmallChangeSysApp {public static void main(String[] args) {new SmallChangeOOP().menu();}
}
24.11.9——343/910这周状态有点小差另外这章真的好多学的比较慢。。。明天把作业写了~