java基础-5 : 面向对象
一.封装
1..构造方法
构造方法是 Java 类中的一个特殊方法,用于在创建对象时初始化对象的成员变量。它的主要特点是:
方法名必须与类名完全相同(包括大小写)。
没有返回类型(连
void
也不能写)。在
new
对象时自动调用,不能手动调用。
(1) 默认构造方法(无参构造方法)
如果类中没有显式定义任何构造方法,Java 会自动提供一个默认的无参构造方法(内容为空)。
但如果定义了任意构造方法,Java 不再提供默认构造方法,此时如果需要无参构造,必须手动编写。
public class Person {private String name;// 默认构造方法(如果没写任何构造方法,Java会自动生成)public Person() {System.out.println("调用了无参构造方法");}
}
(2) 带参数的构造方法
可以在构造方法中接收参数,用于初始化对象的成员变量。
public class Person {private String name;// 带参数的构造方法public Person(String name) {this.name = name; // 用 this 区分成员变量和参数}
}
2.getter/setter
针对私有变量,都要提供对应的getter和setter方法
getter:
get + 首字母大写的字段名
(无参数,返回字段值)setter:
set + 首字母大写的字段名
(带参数,无返回值)
package test;public class friend {private String name;private int age;public friend(){System.out.println("无参构造方法");}public friend(String name,int age){this.name = name;this.age = age;}// 在成员变量与局部变量中,如果变量名相同,那么局部变量会覆盖成员变量,既就近原则,需要对成员变量使用thispublic void setName(String name){this.name = name;}
// 获取成员变量的值,不需要参数,需要返回值public String getName(){return name;}public void setAge(int a){if(a>=18&&a<30){age = a;}else{System.out.println("年龄不合法");}}public int getAge(){return age;}
}
3.练习1
定义一个things类,私有化成员变量,构造有参,无参方法,设置setter/getter方法
package test;public class things {private int id;private String name;private int price;private int number;public things() {}public things(int id, String name, int price, int number) {this.id = id;this.name = name;this.price = price;this.number = number;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public int getNumber() {return number;}public void setNumber(int number) {this.number = number;}
}
定义一个数组,并添加2个things对象
package test;public class test2 {public static void main(String[] args){things[] arr = new things[3];things t1 = new things(1,"apple",10,10);things t2 = new things(2,"banana",20,20);things t3 = new things(3,"orange",30,30);arr[0] = t1;arr[1] = t2;arr[2] = t3;for(int i = 0;i < arr.length;i++){System.out.println(arr[i].getId() + " " + arr[i].getName() + " " + arr[i].getPrice() + " " + arr[i].getNumber());}}
}
3.练习2
定义一个角色类
package test;import java.util.Random;public class Role {private String name;private int blood;private char gendar;private String face;String[] boyface = {"男1","男2","男3","男4","男5"};String[] girlface = {"女1","女2","女3","女4","女5"};// 构造方法public Role() {System.out.println("无参构造方法");}public Role(String name, int blood,char gendar) {this.name = name;this.blood = blood;this.gendar = gendar;setFace(gendar);}// getter和setter方法public void setName(String name) {this.name = name;}public String getName() {return name;}public int getBlood() {return blood;}public void setBlood(int blood) {this.blood = blood;}public void setFace(char gendar){Random r = new Random();if(gendar=='男'){int index = r.nextInt(boyface.length);this.face = boyface[index];}else if(gendar=='女'){int index = r.nextInt(girlface.length);this.face = girlface[index];}else{this.face = "人妖";}}public String getFace(){return face;}public void attack(Role role) {Random r = new Random();int hurt = r.nextInt(20) + 1;int remainblood = role.getBlood() - hurt;remainblood = remainblood < 0 ? 0 : remainblood;role.setBlood(remainblood);// this代表方法调用者System.out.println(this.name + "攻击了" + role.getName() + ",造成了" + hurt+ "点伤害" + role.getName() + "剩余血量为" + remainblood);}
}
package test;public class test {public static void main(String[] args) {Role r1 = new Role("张三",100,'男');Role r2 = new Role("李四",100,'男');while(true){r1.attack(r2);if(r2.getBlood()==0){System.out.println(r2.getName() + "被击杀");break;}r2.attack(r1);if(r1.getBlood()==0){System.out.println(r1.getName() + "被击杀");break;}}}
}
二.继承
单继承:Java类只能直接继承一个父类
传递性:继承关系可以多层传递
构造方法不继承:但子类必须调用父类构造器
Object类:所有类的终极父类
extends: java使用extends实现单继承
class Animal {public String name;protected int age;private String secret; // 子类不能直接访问public Animal(){}public Animal(String name, int age) {this.name = name;this.age = age;this.secret = "Animal secret";System.out.println("Animal构造方法被调用");}// 可被子类重写的方法public void makeSound() {hiddenMethod();System.out.println(name + "动物发出了声音");}// private方法 - 对子类不可见private void hiddenMethod() {System.out.println("动物私有方法");}// final方法 - 不能被子类重写public final void breathe() {System.out.println(name + "动物呼吸");}// static方法 - 继承但不重写public static void describe() {System.out.println("类方法");}
}
// 2. 单继承 extends
class Dog extends Animal {// 新增属性private String breed;public Dog(){super();}// 构造方法必须调用父类构造器public Dog(String name, int age, String breed) {super(name, age); // 必须放在第一行this.breed = breed;System.out.println("Dog构造方法被调用");}// 方法重写(Override)@Overridepublic void makeSound() {System.out.println(name + "狗叫");}// 新增方法public void fetch() {System.out.println(name + " is fetching");}// 尝试重写static方法 - 实际上是隐藏(hiding)而非重写public static void describe() {System.out.println("This is a Dog class");}// 重写toString,使用super调用父类方法@Overridepublic String toString() {return super.toString() + "[breed=" + breed + "]";}
}
// 3. 多层继承
class Puppy extends Dog {public Puppy(String name, int age, String breed) {super(name, age, breed);System.out.println("Puppy构造方法被调用");}@Overridepublic void makeSound() {System.out.println(name + " yelps: Yip yip!");}
}
1.构造方法
子类构造器必须调用父类构造器
如果子类构造器没有显式调用:
- 默认调用父类无参构造器
super()
- 如果父类没有无参构造器,编译报错
2.方法重写
子类重新定义父类已有的方法
必须遵守"两同两小一大"规则:
- 两同:方法名相同、参数列表相同
- 两小:返回值类型相同或是子类、抛出的异常相同或是子类
- 一大:访问权限相同或更大
3.super关键字
访问父类的成员变量:
super.variable
调用父类的方法:
super.method()
调用父类构造器:
super(...)
(必须放在子类构造器第一行)
public class test3 {public static void main(String[] args) {zi z = new zi();z.print();z.move();}
}
class fu{String name = "123";public void eat(){System.out.println("fu eat");}public void sleep(){System.out.println("fu sleep");}
}
class zi extends fu{String name = "456";public void print(){String name = "789";System.out.println(name);System.out.println(this.name);System.out.println(super.name);}public void move(){this.eat();super.eat();}@Overridepublic void eat(){System.out.println("zi eat");}@Overridepublic void sleep(){System.out.println("zi sleep");}
}
789
456
123
zi eat
fu eat
4.final关键字与继承
final class
:禁止被继承(如String类)final method
:禁止被子类重写final variable
:常量,不可修改
5.抽象类与继承
抽象类(
abstract class
)必须被继承才能使用
可以包含抽象方法(只有声明没有实现)
子类必须实现所有抽象方法,除非子类也是抽象类
// 1. 抽象类和抽象方法
abstract class Shape {protected String color;public Shape(String color) {this.color = color;}// 抽象方法 - 必须被子类实现public abstract double area();// 具体方法public String getColor() {return color;}
}
// 实现抽象类
class Circle extends Shape {private double radius;public Circle(String color, double radius) {super(color);this.radius = radius;}@Overridepublic double area() {return Math.PI * radius * radius;}// 重写Object的equals方法@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (!(obj instanceof Circle)) return false;Circle other = (Circle) obj;return Double.compare(radius, other.radius) == 0&& color.equals(other.color);}
}
1.在继承中构造方法不会被继承因为,构造方法的方法名和类名相同,当一个类中没有构造方法时,会默认生成一个无参构造方法,
2.成员变量可以被继承,私有(private)或非私有(如public)不过private需要通过getter和setter方法来访问
虚方法表:1.非private,非static,非final的方法
3.成员方法:虚方法表可以,否则不行
三.多态
继承关系:存在父子类关系
方法重写:子类重写父类方法
向上转型:父类引用指向子类对象
1.调用成员变量:编译看左边,运行看左边
- 编译看左边,左边是Animal,Animal中没有name属性,则编译报错
- 运行看左边:java在运行时,实际获取的是左侧
2.调用成员方法:编译看左边,运行看右边
- 因为成员方法中,子类重写了会把虚方法表里的内容覆盖
- 多态的弊端: 不能调用子类的特有方法,因为编译看左侧,左侧没有,所以报错
- 解决方案:进行强制转换
public class Person {private String name;private int age;public Person(){}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 void show(){System.out.println("我叫"+name+",年龄"+age);}
}
//子类1
public class Student extends Person{@Overridepublic void show(){System.out.println("我是学生:"+getName()+"年龄:"+getAge());}
}
//子类2
public class Admin extends Person{@Overridepublic void show(){System.out.println("我是管理员:"+getName()+"年龄:"+getAge());}
}
//子类3
public class Teacher extends Person{@Overridepublic void show(){System.out.println("我是老师:"+getName()+"年龄:"+getAge());}
}
public class 多态 {public static void main(String[] args) {Person p1 = new Admin();Person p2 = new Student();Person p3 = new Teacher();
// 方法一:
// 先判断是否为Dog类型,如果是,则进行强制转换,转变变量名为d1
// 如果不是,则不进行强制转换,结果直接为falseif(p1 instanceof Admin a){a.setName("admin");a.show();}if(p2 instanceof Student s){s.setName("student");s.show();}
// 方法二:直接使用强转if(p3 instanceof Teacher){Teacher t1 = (Teacher) p3;t1.show();}}public static void register(Person p){p.show();}
}
我是管理员:admin年龄:0
我是学生:student年龄:0
我是老师:null年龄:0