前言
尚硅谷B站公开课学习笔记
第一天
基础格式部分
-
java程序编写-编译-运行的过程
编写:我们将编写的java代码保存在以".java"结尾的源文件中
编译:使用javac.exe命令编译我们的java源文件。格式:javac 源文件名.java
运行:使用java.exe命令解释运行我们的字节码文件。 格式:java 类名 -
在一个java源文件中可以声明多个class。但是,只能最多有一个类声明为public的。
而且要求声明为public的类的类名必须与源文件名相同。
文件名是Main.java那么public就只能加到Main类前面。
-
程序的入口是main()方法。格式是固定的。
-
输出语句:
System.out.println():先输出数据,然后换行
System.out.print():只输出数据 -
每一行执行语句都以";"结束。
-
编译的过程:编译以后,会生成一个或多个字节码文件。字节码文件的文件名与java源文件中的类名相同。只能运行包含main方法的类
如图所示,红色箭头所指的名字要相同,当然可以不是Main,但要相同,并且public只能加在它前面。(注意,这并不是说只有它可以运行)
蓝色箭头所指的是另一个类,它不能加public,因为已经有人加了。
并且值得注意的是,一个类只有包含了main方法才可以执行,
变量与运算符
关键字和保留字
标识符
凡是可以自己起名字的地方都叫标识符,类名、变量名、方法名、接口名……
标识符有自己的命名规则,和C差不多,不过多了个$可以用,还是数字不能开头
变量
变量类型、变量名、存储的值,和C一样的
多了个byte,这样就能1、2、4、8了
注意!声明long型变量必须以"l"或"L"结尾
注意!声明float型变量必须以"f" 或"F"结尾
long l1=31415926L;
第二天
Java学习的三条主线
封装性
加public表示是全局类,这个public类可以被所有类调用,即可以import导包到任何类中;
其余的没加public的表示保留类,只能被本包中的其他类调用。
类的内部成员可以使用四种权限修饰符修饰
构造器
此处的People()就是一个无参构造器,任何类都会有一个构造器,包括抽象类
构造器主要有两个作用
1.搭配new关键字,创建类的对象
2.在创建对象的同时,可以给对象的相关属性赋值
构造器的使用说明
1.构造器声明的格式:权限修饰符 类名(形参列表){ }
2.创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限与类声明的权限相同
3.一旦类中显示声明了构造器,则系统不再提供默认的空参构造器
4.可以声明多个构造器,彼此之间构成重载关系
5.注意:构造器不是方法,它和方法没关系
实例变量与类变量
public class UserTest {
public static void main(String[] args) {
//实例变量,每一个对象都有一份
User u1 = new User();
User u2 = new User();
//后面有加static修饰的静态变量(类变量)
//类变量是每个对象共用的
}
}
class User{
//属性(或实例变量)
//实例,就是对象
//实例变量,就是这两个变量归于具体的对象所有
String name;
int age;
}
/**
* 一、类中属性(当前仅考虑实例变量)赋值过程
* 1.在类的属性中,有哪些位置可以给属性赋值?
* ①默认赋值 ②显式赋值 ③构造器中赋值
* ④通过“对象.方法”赋值 ⑤通过“对象.属性”的方法赋值
* 2.这些位置执行的先后顺序是怎样的?
* ① - ② - ③ - ④/⑤
* 其中①、②、③只能执行一次,④、⑤可以执行多次
*/
class moren{//默认赋值
int a;
}
class xianshi{//显式赋值
int a = 5;
}
class gouzao{//构造器中赋值
int b;
gouzao(int b){
this.b = b;
}
}
实例方法与类方法
在Java中,函数要加上static
关键字才能被称为静态方法(static method)。这是因为Java中的方法分为两种类型:实例方法(instance method)和静态方法(static method)。
-
实例方法(非静态方法):
实例方法是与对象实例相关联的方法,也就是说,只有在创建类的对象后才能调用这些方法。在实例方法内部,可以访问和操作对象的实例变量。实例方法是非静态方法,因为它们依赖于类的实例存在。 -
静态方法:
静态方法不与任何对象实例相关联,它们属于整个类而不是类的实例。静态方法在类加载时就已经存在,并且可以直接通过类名调用,不需要创建类的对象。由于静态方法不依赖于实例变量,所以在静态方法内部不能直接访问实例变量。
为了在Java中调用一个方法,必须先通过类创建一个对象,然后通过对象调用实例方法。但是,如果一个方法在执行过程中不需要访问实例变量,或者不依赖于类的实例状态,那么就可以将该方法声明为静态方法,从而避免创建对象的开销,并且可以直接通过类名调用。
例子:
public class MyClass {
// 静态方法
public static void staticMethod() {
// 可以在静态方法中调用其他的静态方法
}
// 实例方法
public void instanceMethod() {
// 可以在实例方法中调用其他实例方法以及静态方法
}
}
可以不加static
吗?
答案是可以的,但这取决于你的需求。如果方法需要访问实例变量或者与对象的状态相关,那么它必须声明为实例方法,此时不能加static
关键字。如果方法不需要访问实例变量或者与对象状态无关,那么可以将其声明为静态方法,并在方法名前加上static
关键字。
总结:
- 静态方法不依赖于类的实例,可以直接通过类名调用。
- 实例方法依赖于类的实例,需要先创建类的对象才能调用。
this的使用
/**
* this关键字的使用
* 1.使用形参num给属性num赋值时,this.num代表属性,num代表形参
* 2.this可以调用成员变量、方法、构造器,不能调用局部变量
* 3.this指的是当前对象(在方法中调用时)或当前正在创建的对象(在构造器中调用)
* this调用属性和方法
* 针对方法内的使用情况(准确的说是非static修饰的方法)
* 一般情况:通过对象调用方法,可以在方法内调用当前对象的属性或其他方法,我们可以在前面加this.但是一般情况下我们会省略
* 特殊情况:如果方法的形参和对象的属性同名了,那么要用this.来指明哪个是对象的属性
* 针对构造器内的使用情况,我们可以在类的构造器中,调用当前类中指定的其它构造器,注意,调用其他构造器的语句必须声明在当前构造器的首行
* 在一个构造器中,最多有一个this(形参)
* 如果一个类中声明了n个构造器,则最多有n-1个构造器中有this(形参)
*/
public class this_user {
String name;
int age;
public this_user(){
//模拟对象创建时,需要初始化50行代码
}
public this_user(String name){
this();
//直接使用this()代表调用当前对象的空参构造器
//注意不要携程this_user()了,也没有this.this_user()
this.name = name;
}
public this_user(String name,int age){
this(name);
//也可以使用this(参数)来调用当前对象的带参构造器
this.age = age;
}
}
第三天
第一个案例
package day03.exer3;
import java.util.Scanner;
/**
* CMUtility工具类:
* 将不同的功能封装为方法,就是可以直接通过调用方法使用它的功能,而无需考虑具体的功能实现细节。
*
* @author 尚硅谷-宋红康
* @create 17:17
*/
public class CMUtility {
private static Scanner scanner = new Scanner(System.in);
/**
用于界面菜单的选择。该方法读取键盘,如果用户键入’1’-’5’中的任意字符,则方法返回。返回值为用户键入字符。
*/
public static char readMenuSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false);
c = str.charAt(0);
if (c != '1' && c != '2' &&
c != '3' && c != '4' && c != '5') {
System.out.print("选择错误,请重新输入:");
} else break;
}
return c;
}
/**
从键盘读取一个字符,并将其作为方法的返回值。
*/
public static char readChar() {
String str = readKeyBoard(1, false);
return str.charAt(0);
}
/**
从键盘读取一个字符,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static char readChar(char defaultValue) {
String str = readKeyBoard(1, true);
return (str.length() == 0) ? defaultValue : str.charAt(0);
}
/**
从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
*/
public static int readInt() {
int n;
for (; ; ) {
String str = readKeyBoard(2, false);
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
从键盘读取一个长度不超过2位的整数,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static int readInt(int defaultValue) {
int n;
for (; ; ) {
String str = readKeyBoard(2, true);
if (str.equals("")) {
return defaultValue;
}
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
从键盘读取一个长度不超过limit的字符串,并将其作为方法的返回值。
*/
public static String readString(int limit) {
return readKeyBoard(limit, false);
}
/**
从键盘读取一个长度不超过limit的字符串,并将其作为方法的返回值。
如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值。
*/
public static String readString(int limit, String defaultValue) {
String str = readKeyBoard(limit, true);
return str.equals("")? defaultValue : str;
}
/**
用于确认选择的输入。该方法从键盘读取‘Y’或’N’,并将其作为方法的返回值。
*/
public static char readConfirmSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
private static String readKeyBoard(int limit, boolean blankReturn) {
String line = "";
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (line.length() == 0) {
if (blankReturn) return line;
else continue;
}
if (line.length() < 1 || line.length() > limit) {
System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
package day03.exer3;
public class Customer {
private String name;
private char gender;
private int age;
private String phone;
private String email;
public Customer() {
}
public Customer(String name, char gender, int age, String phone) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
}
public Customer(String name, char gender, int age, String phone, String email) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
package day03.exer3;
public class CustomerList {
private Customer[] customers;
private int total = 0;
public CustomerList(int totalCustomer){
customers = new Customer[totalCustomer];
}
public boolean addCustomer(Customer customer){
if(total<customers.length-1){
customers[total++] = customer;
return true;
}else{
return false;
}
}
public boolean replaceCustomer(int index, Customer cust){
if(index>=0 && index<total){
customers[index] = cust;
return true;
}else{
System.out.println("插入位置非法");
return false;
}
}
public boolean deleteCustomer(int index){
if(index>=0 && index<total){
for(int i=index;i<total;i++){
customers[i] = customers[i+1];
}
total--;
return true;
}else{
System.out.println("删除位置非法");
return false;
}
}
public Customer[] getAllCustomers(){
return customers;
}
public Customer getCustomer(int index){
return customers[index];
}
public int getTotal(){
return total;
}
}
package day03.exer3;
import static day03.exer3.CMUtility.*;
public class CustomerView {
CustomerList customerList = new CustomerList(10);
public void enterMainMenu(){
boolean loopFlag = true;
String mainView = """
-----------------拼电商客户管理系统-----------------
1 添 加 客 户
2 修 改 客 户
3 删 除 客 户
4 客 户 列 表
5 结 束 操 作
请选择(1-5):
""";
System.out.println(mainView);
char choice;
while (loopFlag){
choice = readMenuSelection();
if(choice == '1'){
addNewCustomer();
System.out.println(mainView);
}
if(choice == '2'){
modifyCustomer();
System.out.println(mainView);
}
if(choice == '3'){
deleteCustomer();
System.out.println(mainView);
}
if(choice == '4'){
listAllCustomers();
System.out.println(mainView);
}
if(choice == '5'){
loopFlag = false;
}
}
}
private void addNewCustomer(){
String name;
char sex;
int age;
String number;
String email;
System.out.println("---------------------添加客户---------------------\n");
System.out.println("姓名:");
name = readString(30,"?");
System.out.println("性别:");
sex = readChar('?');
System.out.println("年龄:");
age = readInt(-1);
System.out.println("电话:");
number = readString(30,"?");
System.out.println("邮箱:");
email = readString(30,"?");
if(customerList.addCustomer(new Customer(name,sex,age,number,email))){
System.out.println("---------------------添加完成---------------------\n");
}else {
System.out.println("-----------------超出容量,添加失败-----------------\n");
}
}
private void modifyCustomer(){
System.out.println("---------------------修改客户---------------------");
System.out.println("请选择待修改客户编号(-1退出):");
int choice = readInt();
if(choice != -1){
if(choice<0 || choice>=customerList.getTotal()){
System.out.println("---------------------无该用户---------------------");
}else{
Customer customer = customerList.getCustomer(choice);
System.out.println("----------各项修改过程中直接回车表示不修改此项----------");
System.out.println("姓名("+customer.getName()+"):");
String name = readString(30,"-1");
if(!name.equals("-1")){
customer.setName(name);
}
System.out.println("性别("+customer.getGender()+"):");
char sex = readChar('\n');
if(sex!='\n'){
customer.setGender(sex);
}
System.out.println("年龄("+customer.getAge()+"):");
int age = readInt(-1);
if(age != -1){
customer.setAge(age);
}
System.out.println("电话("+customer.getPhone()+"):");
String number = readString(30,"\n");
if(!number.equals("\n")){
customer.setPhone(number);
}
System.out.println("邮箱("+customer.getEmail()+"):");
String email = readString(30,"\n");
if(!number.equals("\n")){
customer.setEmail(number);
}
System.out.println("---------------------修改完成---------------------");
}
}
}
private void deleteCustomer(){
System.out.println("---------------------删除客户---------------------");
System.out.println("请选择待删除客户编号(-1退出):");
int choice = readInt();
if(choice != -1){
if(choice<0 || choice>=customerList.getTotal()){
System.out.println("---------------------无此用户---------------------");
}else{
System.out.println("确认是否删除(Y/N):");
char choice1 = readConfirmSelection();
if(choice1 == 'Y'){
customerList.deleteCustomer(choice);
System.out.println("---------------------删除完成---------------------");
}else{
System.out.println("---------------------取消成功---------------------");
}
}
}
}
private void listAllCustomers(){
System.out.println("---------------------------客户列表---------------------------\n");
System.out.println("编号\t姓名\t性别\t年龄\t电话\t\t邮箱");
for(int i = 0;i<customerList.getTotal();i++){
Customer customer = customerList.getCustomer(i);
System.out.println(i+1+"\t"+customer.getName()+"\t"+customer.getGender()+"\t"+customer.getAge()+"\t"+customer.getPhone()+"\t\t"+customer.getEmail());
}
System.out.println("-------------------------客户列表完成-------------------------\n");
}
public static void main(String[] args){
CustomerView customerView = new CustomerView();
customerView.enterMainMenu();
}
}
三大特性之继承性
package day04;
/**
* 继承
* 1.从上而下的继承,人---教师、学生
* 2.从下而上的继承,猫、狗---动物
* is-a的关系
* 继承描述事物之间的所属关系,它让类与类之间产生了is-a的关系,为多态的使用提供了前提
* 要注意这种is-a的含义,比如dog is a annimal,而不是dog is a cat
*/
public class jicheng_1 {
}
class A{
int a;
}
class B extends A{
}
package day04;
class ManKind{
private int sex;
private int salary;
public ManKind(){
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
void ManOrWoman(){
if(sex == 1){
System.out.println("man");
}else if (sex == 0) {
System.out.println("woman");
}else{
System.out.println("无性别");
}
}
void employeed(){
if(salary != 0){
System.out.println("有工作");
}else{
System.out.println("没工作");
}
}
}
class Kids extends ManKind{
private int yearsOld;
//子类构造器第一句必须是super(参数/无参)
//同时,子类本身的构造器也可以因为参数而进行重载
//二者结合,有很多种可能,以下列举了四个可能的子类构造器
public Kids(int age){
super();
this.yearsOld = age;
}
public Kids(int sex, int salary) {
super(sex, salary);
}
public Kids(int sex, int salary,int age) {
super(sex, salary);
this.yearsOld = age;
}
// public Kids(int sex, int salary,int age) {//错误写法
// this.yearsOld = age;
// //Call to 'super()' must be first statement in constructor body
// super(sex, salary);
// }
void printAge(){
System.out.println(yearsOld);
}
}
1.有了继承性以后:
> 子类就获取到了父类中声明的所有的属性和方法
> 但是由于封装性的存在,子类可能不能直接调用父类中声明的属性或方法
> 子类在继承父类以后,还可以扩展自己特有的功能,比如增加特有的属性、方法
2.关于构造方法
> 只有子类构造可以调用父类构造,普通子类方法无法调用构造器
> 子类构造方法中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造
> 子类构造可以通过super(参数)来调用父类重载构造
> super的父类构造调用,必须是子类构造方法的第一个语句,并且不能一个子类构造调用多次super构造
> 总之,子类必须调用父类构造方法,不写则赠送隐含super(),写了就用写的那个super
> super只能有一个,而且必须是第一个
class Kids extends ManKind{
private int yearsOld;
//子类构造器第一句必须是super(参数/无参)
//同时,子类本身的构造器也可以因为参数而进行重载
//二者结合,有很多种可能,以下列举了四个可能的子类构造器
public Kids(int age){
super();
this.yearsOld = age;
}
public Kids(int sex, int salary) {
super(sex, salary);
}
public Kids(int sex, int salary,int age) {
super(sex, salary);
this.yearsOld = age;
}
// public Kids(int sex, int salary,int age) {//错误写法
// this.yearsOld = age;
// //Call to 'super()' must be first statement in constructor body
// super(sex, salary);
// }
void printAge(){
System.out.println(yearsOld);
}
}
3.默认的父类
Java中声明的类,如果没有显式的声明其父类时,则默认继承于java.lang.Object
4.Java支持多层继承,但是一个子类不能继承多个父类
5.四种权限修饰
修饰符 本类内部 本包内 其他包的子类 其他包的非子类
---------------------------------------------------------------
private √ × × ×
缺省 √ √ × ×
protected √ √ √ ×
public √ √ √ √
外部类用public、缺省修饰
成员变量、方法、构造器、内部类用public、protected、缺省、private修饰
6.关于import
加public表示是全局类,这个public类可以被所有类调用,
即可以import导包到任何类中,包括其它包中的类
其余的没加public的表示保留类,只能被本包中的其他类调用,
并且,调用同一个包里的类不用import,但是如果
包里还有子包,子包里有一个类和包里的类重名,那么要写全名称
其他包里要是有重名也可以用这个方法
继承其他包下的类时也需要导包,然而缺省类没法导到其他包的类中,
所以不能继承其他包中的缺省类
import的时候可以导高一些的包,方便用xx.xx.xx
public class ExtendTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "tony";
p1.age =18;
Person p2 = new Person();
day04.exer2.Person p3 = new day04.exer2.Person();
Student s1 = new Student();
s1.name = "tony";
}
}
二、方法的重写(override)
1.为什么需要方法的重写?
子类在继承父类以后,就获取了父类中声明的所有方法。但是,父类中的方法可能不太适用于子类,换句话说,子类需要对父类继承过来的方法进行覆盖、覆写的操作
2.方法重写的规则
[复习] 方法声明的格式:权限修饰符 返回值类型 方法名(形参列表) { //方法体 }
具体规则:
① 父类被重写的方法与子类重写的方法,方法名和形参列表必修相同。(只有这样,系统才能判断出重写的是哪一种方法)
② 权限修饰符可以不同,子类重写的方法的权限修饰符,不小于父类被重写的方法的权限修饰符。(比如父类缺省、子类public)
-- 特例:子类不能重写父类中权限为private的方法,哪怕满足方法名、形参相同,此时也会视为是子类创建的新方法,不会覆盖父类原本的方法
③ 关于返回值类型:
> 父类被重写的方法返回值类型是引用数据类型,则子类重写的方法的返回值类型要“小于等于”父类的
> “小于等于”:与父类返回值类型相同,或者是父类返回值的子类
> 父类被重写的方法返回值类型是其他的,则子类重写的方法的返回值类型必须和父类一样
3.方法的重载,名字必须相同,参数列表必须不同,返回值可以不同,方法体可以不同,同一个类,多个版本一起使用
方法的重写:名字必须相同,参数列表必须相同,返回值类型有规则,方法体可以不同,不同的类,覆盖、替换父类的方法
super关键字的使用
super和this差不多
一、super关键字的使用
1.为什么需要super?
举例1:子类继承父类之后,对父类的方法进行了重写,那么在子类中,是否还可以对父类中被重写的方法进行调用?
举例2:子类继承父类以后,发现子类和父类中定义了同名的属性,是否可以在子类中区分两个同名的属性?(注意,属性是不会重写的)如何调用?
2.super的理解:父类的
3.super可以调用的结构:属性、方法、构造器,和this比较像
3.1 super调用属性、方法
子类继承父类后,我们就可以在子类的方法或构造器中,调用父类中声明的属性或方法。(满足封装性的前提下)
如何调用呢?需要使用“super.”结构,表示调用父类的属性或方法
一般情况下,我们可以考虑省略“super.”的结构,但是,如果出现子类重写了父类的方法或子父类中出现了同名的属性时,则必须使用“super.”的声明,显式的调用
父类被重写的方法或父类中声明的同名的属性。(在实际开发中一定要避开这种同名的状况,不要自找麻烦)
3.2 super调用父类构造器
> 只有子类构造可以调用父类构造,普通子类方法无法调用构造器
> 子类构造方法中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造
> 子类构造可以通过super(参数)来调用父类重载构造
> super的父类构造调用,必须是子类构造方法的第一个语句,并且不能一个子类构造调用多次super构造
> 总之,子类必须调用父类构造方法,不写则赠送隐含super(),写了就用写的那个super
> super只能有一个,而且必须是第一个
class Kids extends ManKind{
private int yearsOld;
//子类构造器第一句必须是super(参数/无参)
//同时,子类本身的构造器也可以因为参数而进行重载
//二者结合,有很多种可能,以下列举了四个可能的子类构造器
public Kids(int age){
super();
this.yearsOld = age;
}
public Kids(int sex, int salary) {
super(sex, salary);
}
public Kids(int sex, int salary,int age) {
super(sex, salary);
this.yearsOld = age;
}
// public Kids(int sex, int salary,int age) {//错误写法
// this.yearsOld = age;
// //Call to 'super()' must be first statement in constructor body
// super(sex, salary);
// }
void printAge(){
System.out.println(yearsOld);
}
}
三大特性之多态性
什么是多态?
package day05.duotai;
public class Person {
int name;
int age;
int gender;
void love(){
System.out.println("我的爱好是爱好");
}
}
package day05.duotai;
public class Man extends Person{
@Override
void love(){
System.out.println("我喜欢钓鱼");
}
}
package day05.duotai;
public class Woman extends Person{
@Override
void love(){
System.out.println("我喜欢逛街");
}
}
package day05.duotai;
public class duotai_test {
public static void main(String[] args) {
Person human1 = new Man();
Person human2 = new Woman();
human1.love();
human2.love();
System.out.println(human1);
}
}
以上四段代码,分别是Person类的定义以及它的两个子类Man和Woman的定义。
其中,我们在Person类中设立了爱好(love)方法,但是出于实际考虑,每个人的爱好都是不同的,我们不可能根据每个人去设立这个方法。当然,你可以说,只要传一个参数就好了,修改一下输出的语句,但是这样做并不是一个长远的方法。引用多态的作用便是,哪怕增加了新的子类,原本父类的方法也无需改变(不用为每个子类去写一个专属于它的“爱好”方法)
多态的前提是类的继承以及子类中对父类方法的重写,将父类的引用指向子类的对象,那么一个引用类型的变量就可能指向多种不同类型的对象,父类中的爱好方法,也会变成各个子类的爱好方法
记住,编译看左边,执行看右边。(编译)声明它的类型是什么,它就拥有什么类型的属性和方法(不能直接用子类拓展出的方法)。通过它执行方法时,哪怕他声明的是Person类,执行的也是子类(Man or Woman)重写过的方法,而且它在执行语句时,实际上也是子类
注意,属性是不会被覆盖的,也就是说,当Person human1 = new Man时,输出human1的名字name,打印的将会是Person类中的默认属性值。当然,我们在继承时提到过,不提倡子类有和父类重名的属性。
向下转型与instanceof关键字的使用
package day05.duotai;
public class duotai_test {
public static void main(String[] args) {
Person human1 = new Man(); //此时human1被编译器识别为Person类
//human1.earnMoney(); 不能直接调用子类特有的结构
//System.out.println(human1.isSmoking);
Man m1 = (Man)human1; //向下转型,使用强转符
m1.earnMoney(); //此时m1被编译器识别为Man类
System.out.println(human1 == m1); //二者指向同一空间
/**
* Person p2 = new Woman();
* Man m2 = (Man)p2;
* 这两句代码,编译是不会报错的,但是执行时会报错
* 编译时,编译器会看左边,认为p2是Person类,所以第二句可以强制转换
* 执行时,编译器会看右边,发现p2实际上是Woman类,不能转换成Man类,他们之间没有父子关系
*/
//instanceof关键字的使用
/**
* public class grammer {
* public static void main(String[] args) {
* Pet[] pets = new Pet[2];
* pets[0] = new Dog();//多态引用
* pets[0].setNickname("小白");
* pets[1] = new Cat();//多态引用
* pets[1].setNickname("雪球");
* for (int i = 0; i < pets.length; i++) {
* pets[i].eat();
* if(pets[i] instanceof Dog){
* Dog dog = (Dog) pets[i];
* dog.watchHouse();
* }else if(pets[i] instanceof Cat){
* Cat cat = (Cat) pets[i];
* cat.catchMouse();
* }
* }
* }
* }
*/
}
}
作业
package day05.exer2;
public class GemometricObject {
protected String color;
protected double weight;
protected GemometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double findArea(){
return 0;
}
}
package day05.exer2;
import static java.lang.Math.PI;
import static java.lang.Math.max;
public class Circle extends GemometricObject{
private double radius;
public Circle(String color, double weight, double radius) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double findArea() {
return Math.pow(radius,2)*PI;
}
}
package day05.exer2;
public class MyRectangle extends GemometricObject{
private double width;
private double height;
public MyRectangle(String color, double weight, double width, double height) {
super(color, weight);
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public double findArea() {
return width*height;
}
}
package day05.exer2;
public class GeometricTest {
public static void main(String[] args) {
Circle c1 = new Circle("blue",3,3);
Circle c2 = new Circle("red",3,3);
System.out.println(equalsArea(c1,c2));
System.out.println(displayGeometricObject(c1));
}
public static int equalsArea(GemometricObject g1,GemometricObject g2){
if(g1 != null && g2 != null){
if(g1.findArea() == g2.findArea()){
return 1;
}else{
return 0;
}
}else{
System.out.println("请勿传入空指针");
return 0;
}
}
public static double displayGeometricObject(GemometricObject g1){
return g1.findArea();
}
}
第四天
接口
package day11.apply;
/**
* @BelongsProject: untitled2
* @BelongsPackage: day11.apply
* @Author: Liuruij
* @CreateTime: 2023-09-22 21:27
* @Description: 接口的多态性
* @Version: 1.0
*/
public class USBTest {
public static void main(String[] args) {
//1.创建 接口实现类 的 对象
Computer computer = new Computer();
Printer printer = new Printer();
//此处调用方法时就利用了多态性
//方法说要USB对象,传给方法的是实现了USB接口的打印机对象
computer.transferData(printer);
//2.创建 接口实现类 的 匿名对象
computer.transferData(new Camera());
//3.创建 接口匿名实现类 的 对象
USB usb1 = new USB(){
@Override
public void start(){
System.out.println("U盘开始工作");
}
@Override
public void stop() {
System.out.println("U盘工作完成");
}
};
computer.transferData(usb1);
//4.创建 接口匿名实现类 的 匿名对象
computer.transferData(new USB(){
@Override
public void start(){
System.out.println("固态硬盘开始工作");
}
@Override
public void stop() {
System.out.println("固态硬盘工作完成");
}
});
}
}
class Computer{
//用电脑和一个有usb接口的设备做连接,但是不知道是什么设备
//这个时候就使用多态的概念,usb接口 = 不同设备对象
public void transferData(USB usb){
System.out.println("设备连接成功……");
usb.start();
System.out.println("数据传输的细节……");
usb.stop();
}
}
interface USB{
//声明一些常量,比如USB的长、宽、高、引脚数目……
//方法
void start();
void stop();
}
class Printer implements USB{
//打印机实现USB接口
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机打印完毕");
}
}
class Camera implements USB{
//相机实现USB接口
@Override
public void start() {
System.out.println("相机连接成功,可传输文件到设备");
}
@Override
public void stop() {
System.out.println("文件传输完毕");
}
}
接口的使用
1. 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守。
> 接口体现的大多是一种功能的封装,比如子弹同时具有可以飞和攻击性两种属性
> 在开发当中,继承一般都是体现在抽象类或是接口的继承上,纯粹的类与类之间的继承关系比较少
2. 定义接口的关键字:interface
3. 接口内部结构的说明:
> 可以声明:
属性:必须使用public static final修饰
方法:jdk8之前:声明抽象方法,修饰为public abstract
jdk8:声明静态方法、默认方法
jdk9:声明私有方法
> 不可以声明:构造器、代码块等
4. 接口与类的关系 :实现关系
5. 格式:class A extends SuperA implements B,C{}
A相较于SuperA来讲,叫做子类
A相较于B,C来讲,叫做实现类。
6. 满足此关系之后,说明:
> 类可以实现多个接口。
> 类针对于接口的多实现,一定程度上就弥补了类的单继承的局限性。
> 类必须将实现的接口中的所有的抽象方法都重写(或实现),方可实例化。否则,此实现类必须声明为抽象类。
7. 接口与接口的关系:继承关系,且可以多继承
8. 接口的多态性: 接口名 变量名 = new 实现类对象;
9. 面试题:区分抽象类和接口
> 共性:都可以声明抽象方法
都不能实例化
> 不同:① 抽象类一定有构造器。接口没有构造器
② 类与类之间继承关系,类与接口之间是实现关系,接口与接口之间是多继承关系