面对对象的三大特征
- 封装,继承,多态
封装
- 封装介绍:封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作。总的来说就是相当于一个公司把他的一个技术封装好可以卖出去,使用方只能使用这个技术,而不能看到源码以及修改方法。
- 封装步骤:
- 将属性进行私有化
- 提供一个public公共的set和get方法,用于对属性的赋值和获取值的属性
- 通过对set和get方法的操作,可以实现控制输入的字符数、数值的限制、权限的限制,使其能够完成更多的业务要求。
- 在构造器中也可以调用set方法实现封装。
- 例子:设置一个封装类实现对姓名,薪水,密码的限制
public class AccountTest {
public static void main(String[] args) {
Account j = new Account("j56", 30, "5656565");
System.out.println(j.name + " " + j.balance + " " + j.password);
}
}
class Account {
String name;
double balance;
String password;
public Account() {
}
//将有参构造函数同set方法防止使用者利用创建对象时赋值绕过set方法的限制。
public Account(String name, double balance, String password) {
this.setName(name);
this.setBalance(balance);
this.setPassword(password);
}
public void setName(String name) {
if (name.length() == 2 || name.length() == 3 || name.length() == 4) {
this.name = name;
}else {
System.out.println("姓名的长度应为2,3位或4位");
this.name = "默认"; //加入默认值,其他的set方法同理
}
}
public void setBalance(double balance) {
if (balance > 20) {
this.balance = balance;
}else {
System.out.println("余额应大于20");
}
}
public void setPassword(String password) {
if (password.length() > 6) {
this.password = password;
}else {
System.out.println("密码必须为6位");
}
}
}
- 输出结果:
继承
- 为什么要使用继承:如果有许多类都有很多一样的属性和方法,我们就可以创建一个父类,父类里有共同属性和共同方法,两个子类只需要继承父类,再加上自己的特有属性和特有方法即可。
- 例子:父类
//父类
public class Father {
public String name;
public int age;
public double score;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setScore(double score) {
this.score = score;
}
public void fatherMethdos() {
System.out.println("父类方法被调用");
}
}
子类A:
//子类A
public class A_ extends Father{
public void testing() {
String name1;
name1 = "benshen";
System.out.println("A本身的属性" + name1);
System.out.println("子类A" + name );
}
}
子类B:
//子类B
public class B_ extends Father{
public void testing() {
System.out.println("B类调用" + name);
}
}
测试类:
//测试类
public class TestExtends {
public static void main(String[] args) {
Father father = new Father();
father.setName("klk");
father.fatherMethdos();
A_ a_ = new A_();
a_.setName("名字A");
a_.testing();
B_ b_ = new B_();
b_.testing();
}
}
测试结果:
继承使用的细节
- 子类继承父类所有的属性和方法,但是私有的属性和方法不能使用,但是可以通过公共的方法去访问。
- 例如:
父类:
- 例如:
public class Father {
public int n1 = 100;
protected int n2 = 200;
private int n3 = 300;
int n4 = 400;
public Father() {
}
public int Getn4() { //通过公共函数返回私有属性
return n3;
}
public void test100() {
System.out.println("test100");
}
protected void test200() {
System.out.println("test200");
}
private void test300() {
System.out.println("test300");
}
void test400() {
System.out.println("test400");
}
public void callTest300() { //通过公共函数调用私有函数
test300();
}
}
子类:
public class Sub extends Father{
public Sub() {
}
public void attribute() {
System.out.println("n1:" + n1 + "n2" + n2 + "n4" + n4 + Getn4()); //n3不能调用,因为n3为private
}
public void method() {
test100();
test200();
test400();
callTest300();
// test300(); //错误,因为在父类中test300为private
}
}
测试类:
public class TestExtends {
public static void main(String[] args) {
Sub sub = new Sub();
sub.method();
sub.attribute();
}
}
- 子类创建时必须调用父类的构造器,因为子类在创建时会自动调用super()函数,super函数:默认调用父类构造器。例如:
父类:
子类:
测试:
结果:
- 如果父类无参构造被覆盖,则子类的构造函数会编译错误,需要使用super()函数去指定父类的构造器。
- 如果想调用父类的无参构造器,可以用super()或者什么都不写。如果想调用父类的有参构造器,则在super()里面加入参数即可。
- super()只能在子类的第一行使用并且与this()不能共存。否则会编译错误。其中this()的作用是调用调用当前类的构造函数。用法为this(参数列表)。
- super()的作用是调用父类构造器,直接影响的是父类。
- 使用ctlr + H即可查看类的继承关系。Object类是所有类的父类。
- 父类构造器的调用不限于直接调用,一直可以追溯到顶层类。ctlr + B可以查看该子类的父类。
- 子类只能继承一个父类,而父类可以被很多子类继承。如果想要实现一个类继承两个类,可以将子类的父类继承另一个类。可以达到一样的效果。
- 不能滥用继承,必须满足是同一种的关系,比如人不能继承音乐。
继承本质:就是查找关系
- 有三个类,继承关系为C -> B -> A,当在主函数中创建C的对象时,在JVM内存中先在方法区创建A、B、C以及顶层的Object类,然后在堆空间中创建三个类的属性地址,以及在常量池中加载与地址对应的属性值。然后在栈中创建C对象时,会将地址指向堆空间的地址。
- 如果在A、B、C三个类中都有
String name
这个属性的话,在C创建的对象中访问name时,会由C开始由下到上访问,如果私有则不可。
super用法
- 可以用来访问父类的属性、方法、构造器;
- 用法:super.属性,super.方法,super(参数列表):构造器。
- super使用细节:
-
- 当子类中有和父类同名的属性和方法时,可以使用super访问。
-
- 当子类和父类的属性方法名不同时,直接使用或者this或者super都是一样的效果。
-
- 使用super遵循就近原则。
-