封装
什么是封装
隐藏对象的属性和方法的实现细节,只对外提供一个公共的访问方法
封装的优点
- 提高代码的复用性
- 提高了安全性
封装的一般方式
-
类用public 或省缺修饰
-
成员变量用private(私有的)修饰,该变量不能用[类名.变量名]或[对象.变量名]访问。(private修饰的变量或方法,只有在本类中可以被使用)
-
对私有的成员变量或静态变量添加set、get方法,该方法为对外的公共的访问方法(用public修饰–>公有的),通过该方法可以对变量进行赋值和获取值。
public A B() { return C; } //这个方法为获取变量值的方法,A为该变量的数据类型,B为get+变量名--->变量名第一个字母大写,C为变量名。 ---------------------------------------------------------------------------------- public void B(A C) { this.C = C; } //这个方法为给变量赋值的方法,A为该变量的数据类型,B为set+变量名--->变量名第一个字母大写,C为变量名。
封装的内容
主要封装的是对外不可见的属性和方法。
可以理解为洗衣服要自己用手洗、烘干等,现在有了洗衣机放进去启动就行了,洗衣机相当于一个的封装类,你不需要知道洗衣机怎么洗的、洗的方法是什么,只需要把衣服放进去启动就行了,把衣服放进去滚筒相当于利用set方法设置值,启动相当于调用的方法,洗衣服的具体过程我们是不知道的它被封装在洗衣机里面也就是相当于封装在一个类里面
案例
public class Student {
private String name;
private int age;//属性私有化对外不可见
int m=9;
//添加set、get方法对外提供公共的访问方法
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 class Test {
public static void main(String[] args) {
//在主入口方法中尽量只调用别的方法
Student stu=new Student();
stu.m=7;
stu.getAge();
stu.getName();
stu.setAge(23);
stu.setName("张三");
/*
stu.name="李四";
stu.age="34";
此处的李四和34不能赋值成功
*/
}
}
继承
什么是继承
将多个类中的相同属性抽取出来,放到一个统一的类中,则该类成为父类,被抽取的类称为子类,子类用关键字extends 类名可以使用父类的方法和属性,这就是继承。
继承的代码格式
访问修饰符 class 子类名 extends 父类名{}
继承的注意事项
- 在Java中值只支持单继承,不支持多继承,即extends 后的父类名只能有一个
- Java中支持多层继承,即A继承B,B继承C,这样是可以的
- 子类只能继承父类的非私有的方法和属性,且子类不能继承父类的构造方法,只能调用。
- 继承体现的关系是"is a"
继承的缺点
增强了类的耦合性
耦合:类与类的关系
开发的原则是高内聚,低耦合。
内聚:类自己完成某件事的能力
继承的好处
- 提高了代码的维护性
- 提高了代码的复用性
- 让类与类产生了关系(继承关系)
继承中成员变量的关系
-
子类中的成员变量名与父类中的成员变量名不一样,调用哪个名字就使用那个变量
-
子类中的成员变量名与父类中的成员变量名一样
在子类中访问一个变量的查找顺序
- 在子类的方法局部范围找,有就使用
- 在子类的成员范围找,有就使用
- 在父类的成员范围找,有就使用
- 如果找不到,就报错。
静态方法和属性是否被继承?
- 静态的方法和属性是属于类的,调用的时候使用类名.方法名调用,不需要继承来完成。如果子类中定义了静态的方法和属性,这是父类的静态方法和属性就被隐藏了。如果想要调用父类的静态方法和属性,可以直接通过父类的方法名.属性或变量名完成。至于是否继承,子类是有继承静态方法和属性,但是被隐藏了,和实例方法和属性不一样。
- 静态属性、方法和非静态的属性都可以被继承和隐藏而不能被重写,因此不能实现多态,不能实现父类的引用可以指向子类的对象,非静态的方法可以被继承和重写,因此可以实现多态
案例
public class Animal {
String name;
int age;
private String sex;
public void m(){
System.out.println("这是非私有方法");
}
private void n(){
System.out.println("这是私有方法");
}
}
public class Dog extends Animal{
public static void main(String[] args) {
Dog dog=new Dog();
dog.age=8;
dog.name="小可爱";
/*
dog.sex="女";
//此处报错
*/
dog.m();
/*
dog.n();
//此处报错
*/
}
}
多态
多态的概念
同一类事物在不同的情况下,表现的状态不同
多态的前提
- 要有继承关系
- 要有对父类方法的重写
- 父类的引用指向子类对象
多态的好处
- 提高了代码的维护性(继承)
- 提高了代码的扩展性(多态,子类对父类功能的重写)
多态的缺点
在父类对子类对象的引用中,父类的引用不能调用子类特有的成员方法和成员变量。如果要使用则需要将父类引用转为子类引用。
多态的特点
- 在访问成员变量时,若父类的引用访问的成员变量在子、父类中同时存在,则输出的是父类的成员变量
- static 修饰的方法不能被子类重写,修饰的变量不能改变,所以在调用时,只能使用类名.方法名或变量名调用
- 在子类实例化对象初始化时,先访问父类构造方法,对父类数据进行初始化
- 在访问成员方法时,若子类对父类的方法进行了重写,则调用的是父类的方法;若没有重写则调用的是父类的方法
多态的实例
抽象
将一组事物中共有的属性和方法(行为)抽取出来
抽象类(共有功能)
抽象类
将一组事物中抽取出来的属性和方法放在一个类中,且该类被abstract修饰,该类称为抽象类。
抽象类的特点
- 该类必须用abstract修饰
- 抽象类中不一定有抽象方法,但有抽象方法的类一定为抽象类
- 抽象类中有构造方法,但不能进行实例化,此处的构造方法用来初始化抽象类的数据(当做父类使用时)。
- 抽象类主要用来供子类继承,抽象类的子类要么是抽象类,要么重写抽象类中的方法
- 抽象类不能实例化,但是可以通过多态间接实例化(父类的引用指向子类)
抽象类中的变量和方法:
1.抽象类中可以有非抽象的变量和方法,有抽象方法的类一定是抽象类
2.抽象方法的重写
(共有功能,但是做的内容不一样),抽象方法必须被public或protected修饰,在缺省的情况下默认为public
1.抽象类中的非抽象方法可以被重写吗?
可以
2.抽象类的静态方法能被重写吗?
不能,重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏.
3.抽象类中的普通方法可以被重写吗?
可以
4…总结
抽象类中非抽象方法:
1)final修饰的方法和静态方法不能重写.
2)子类不能继承的,就不是重写.
3)其它的都可重写.
3.抽象类中的变量
4…abstract与private、final、static会有冲突的原因
abstract是可以让其他继承,private是私有的不能让其他类继承;final修饰的是不可以被重写,但是abstract目的就是为了让子类实现抽象方法;static修饰的方法是可以用类名.方法名实现的不需要子类,abstract修饰的方法是需要让子类实现,它们都是有矛盾的。
子类必须重写父类的某个方法,否则出现编译错误
5.Java抽象类中不能有静态的抽象方法。
抽象类是不能实例化的,即不能被分配内存;而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:抽象类不能被分配内存,而static方法必须被分配内存所以抽象类中不能有静态的抽象方法。
定义抽象方法的目的是重写此方法,但如果定义成静态方法就不能被重写。
抽象类存放的是一类事物共有属性和方法
接口(扩展功能,特有功能)
接口的功能
存放事物的特有功能
接口存放的是某个或某一小类事物的特有功能,通过实现接口可以强制性让实现接口的类实现功能可以规范代码。
接口的特点
- 接口的定义:interface 接口名(){}
- 接口的实现格式:利用implents 接口名
- 接口中的方法全部为抽象方法,JDK1.8以后接口中可以有普通方法但要用的default 或者 static 修饰
- 接口不能进行实例化,且接口没有构造方法
- 接口中的方法默认被 public abstract 修饰,成员变量被public static final 修饰
- 接口中不能有变量,只能有常量,且是静态的。
- 一个类可以实现多个接口,一个类只能继承一个父类,一个父类可以有多个子类
如何使用接口
实现接口用implments 接口名
接口中的静态方法 接口名.静态方法名 调用。静态方法,子类不可以使用,静态变量可以,接口中可以存在默认方法
JDK1.8以后可以存在用default或者static修饰的实例方法,但是如何使用该方法呢?
public interface JDK8Interfce{
static void staticMethod(){
System.out.ptintil("接口中的静态方法");
}
default void defaultMethod(){
System.out.ptintil("接口中的默认方法");
}
}
//实现接口的类
public class JDK8InterImpl implements JDK8Interfce{
//实现接口后,因为默认方法不是抽象方法,所以不重写
}
-
接口中static方法的调用:接口名.方法名 比如:
JDK8Interfce.staticMethod();
-
接口中的默认方法的调用:实现类的对象名.方法名 比如:
new JDK8InterImpl().defaultMethod();
-
默认方法可以实现覆盖,但是覆盖后的方法不能在加default修饰
public class JDK8InterImpl implements JDK8Interfce{
//覆盖默认方法
public void defaultMethod(){
System.out.ptintil("接口中的默认方法");
}
}
- 如果一个类实现了多个接口,在多个接口中同时存在一模一样的static方法和default方法。如果实现类使用static方法不会产生错误,因为静态方法是用-接口名.方法名-调用的。如果实现类使用default方法(多个被实现的接口中同时存在相同的默认方法),那么在实现类中必须重写默认方法,否则会编译失败。
接口中不能有静态的抽象方法
接口中的方法也只能是 public abstract修饰的,不能加上static。接口是不能实例化的,即不能被分配内存,而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:接口不能被分配内存,而static方法必须被分配内存。所以接口中不能有静态的抽象方法。
多用接口,少用抽象类。
选择接口还是选择抽象类?
在选择时尽量选择接口,然后再考虑抽象类。
接口是自上而下:对后面的行为进行规范,在后面要使用行为方法,只要是实现该接口就可以了
抽象类是自下而上:使用抽象类时要先想好我们有哪些子类以及不同子类中都有那些方法和是属性,再进行抽取讲公共的抽取出来放在抽象类(那些子类的父类)中
在应用中的区别:接口是方法的规范,规范方法