目录
面向对象语言的三大特征:封装,继承,多态。
1、封装
问题就来了,什么是封装?
1、概念:
在一般情况下,将重复出现的代码抽取了一个函数,称为代码的封装(也叫做包装)。
然而面向对象的封装:是将类的某些信息,使用不同的访问权限修饰符隐藏起来,不让外界直接访问操作。通过类中向外提供的特定的方法来实现对隐藏信息的操作与访问,方便加入控制语句,主动权在我们自己手中。
2、封装的好处:
- 访问时通过特定的方法访问
- 封装会隐藏类的信息
- 方便加入控制语句
- 方便修改实现
3、封装的具体表现
1、将类中成员变量私有化
将成员变量的属性设置为私有权限,在其他类中就不能任意的访问了。那么如何访问呢?
我们可以向外提供一个公共的方法访问,可以在此方法中加入控制语句。
public class person {
//封装1:将类中成员变量私有化
//将成员变量的属性设置为私有权限,在其他类中就不能任意的访问了
private String name;
int age;
//向外提供一个公共的方法访问,可以在此方法中加入控制语句
public void setName(String name) {
if (name.length() > 0 && name.length() < 6) {
this.name=name;
}
}
public String getName() {
return this.name;
}
}
public class TestPerson {
public static void main(String[] args) {
person p1=new person();
//我们本身在其他类中可以直接对类中的属性进行赋值操作,但是没有办法控制其赋值的内容,如果我们对赋值的内容有要求的话,可以用访问权限修饰符来控制
//p1.name="%^&&^*^(&";//不可控
//因此,可以用访问权限修饰符来控制
p1.setName("sfv");
System.out.println(p1.getName());//输出的结果是sfv
}
}
2、将构造方法私有化
在构造方法中加入控制语句(一般不灵活,用处较少)
单例模式:
让一个类,在程序中只创建了一个唯一的对象。
那么如何不被其他的类创建新对象呢?
这里我们可以将构造方法私有化,在外界就不能随意的创建了。
但是我们要向外界提供获得此对象的方法(此方法是静态的,用static修饰,静态方法访问静态态变量)。外界就可以访问到了。因此在类加载时,我们就只会创建一个对象了。
public class window {
//在类加载时,只创建了一个唯一的对象
static window w = new window();
/*
1、将构造方法私有化,在外界就不能随意的调用了
*/
private window() {
}
/*
2、向外提供获得此对象的方法,静态方法访问静态变量
*/
//1、
public static void getWindow() {
System.out.println(w);
}
//2、
public static window getWindow2(){
return w;
}
}
public class TestWindow {
public static void main(String[] args) {
window.getWindow();//1、
System.out.println(window.getWindow2());//2、
}
}
2、继承
1、概念:
就是将同一类事物中共性的属性和行为进行抽取,定在一个类中(叫基类)。 其他类可以继承基类,就可以拥有基类的功能。 实现代码的复用性。减少了代码的冗余。 以及可以在子类中扩展子类自己特有的功能,而不影响其他类。继承的出现让类之间出现了is-a的关系。
2、继承的优点
- 提高了代码的复用性
- 减少了代码的冗余
- 增强了程序的扩展(在子类中扩招自己的特有的功能而不影响其他类)
- 继承的出现让类与类之间产生了is-a的关系,为多态的使用提供了前提。
3、继承的特点
- 一个类只能直接继承一个类,间接的可以继承多个类。只支持单继承,不支持多重继承。
- 一个父类可以同时拥有多个子类
- 子类继承父类之后,拥有了父类的成员变量和成员方法,但是不能直接访问父类的私有的成员。(这里需要采用方法重写)
- 当一个类没有显示的继承,即没有使用extends关键字,那么这个类默认继承Object类。(Objects这个类是Java体系中最大的类,在这之上没有其他类)
4、继承的构造方法
继承中子类的构造方法会去调用父类的构造方法
子类继承父类时,不会继承父类的构造方法。
只能通过“super(形参列表)”的方式调用父类指定的构造方法。
规定super(形参列表,可有可无),必须声明在构造器的首行。
super(); 因此继承的构造方法是为了保证先对父类成员进行初始化。
public class Dog extends Animals {
public Dog() {
super();//在子类的构造方法首行调用父类的构造方法, 不写默认存在
System.out.println("Dog类无参的构造方法");
}
public Dog(String name, int age) {
super(name, age);//调用父类的有参的构造方法,父类的必须先存在。
System.out.println("Dog类有参的构造方法");
}
}
3、方法重写
1、概念
当父类中方法的实现不能满足子类的需求时,可以在子类中对父类的方法进行重写(覆盖) 这样调用时,就会调用子类中重写的功能。
2、方法重写的要求
- 子类重写的方法的结构必须与父类方法的结构一致。(名称,参数列表相同)
- 方法名、参数列表、返回值也必须一致。(简称什么都一样)
- 访问权限应等于或大于父类方法权限。
(有时在方法重写时要加“@Override”。)
@Override:是Java中的一个注解标签,定义在重写的方法上面,表示此方法是父类重写而来。 也可以不用添加,只要重写的方法结构与父类方法结构一致,也算正确的重写。 这里建议保留:1,编译器可以进行语言验证。2,阅读代码时明确知道此方法是重写的。 构造方法,静态方法,成员变量,不存在重写。
在方法重写时通常需要调用父类中的成员,用关键字super。 super:在子类中用来调用父类中的成员。 (this:表示当前对象,但是supper表示调用的是父类中的成员,而不是表示父类对象)
public class Animal {
//私有的,子类不能访问父类
private String name;
private int 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 eat() {
System.out.println("吃饭");
}
}
public class Xdog extends Dog{
@Override
public void eat(){
super.eat();
//this.eat();//无限循环调用父类
System.out.println("小狗吃肉");
}
public static void xDog(){
System.out.println("小狗很吵闹");
}
}
4、抽象类
这里提到了一个抽象的概念,什么是抽象类呢?
1、概念:
简单来说,使用abstract修饰的类就是抽象类。在一个类中如果包含抽象方法,那么这个类也一定是抽象的。反之,一个类是抽象类,那就不一定包含抽象方法。
2、特点:
主要是在上层定义功能,让子类继承实现。
抽象类不能被创建对象,其他功能与正常类相同,可以有成员变量,成员方法,构造方法。
一个子类如果继承了抽象类,要么重写抽象类中的所有抽象方法,要么将该类也定义为抽象类。
(抽象方法:没有方法体,也使用abstract修饰)为什莫要有抽象方法?
在一些体系结构的顶端类中,有些功能没必要实现,因为不同子类中实现的都不同。
//方法1:用abstract修饰整个类
//方法2:写一个抽象方法
public class Chinese extends Person{
//抽象方法
@Override
public void eat(){
System.out.println("中国人吃饺子");
}
}
//抽象类
public abstract class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//chinese创建对象
public Person() {
}
public abstract void eat();
public void sleep() {
System.out.println("人睡觉");
}
}
5、变量的分类
至今我们学过的变量很多,来总结一下
1、按照数据类型分类
数据类型 | 内容 |
基本数据类型 | byte,short,int,long,float,double,char,boolean |
引用数据类型 | 类,数组(持有的是对象的引用地址) |
2、按照位置分类
成员变量 | 局部变量 | |
类中的位置 | 在类中定义 | 在方法中定义或者方法的参数 |
权限修饰 | 可以使用权限修饰符 | 不可以使用权限修饰符 |
初始化 | 创建对象后,由构造方法自动初始化赋值 | 没有默认初始化值,必须自己定义和赋值 |
生命周期 | 非静态: 随着对象的创建,随着对象的销毁而销毁 静态的: 随着类的加载而加载, 随着类的销毁而销毁 | 方法调用创建,方法运行结束销毁 |
存储位置 | 非静态: 堆 静态的: 方法区 | 栈 |
6、多态
属于Java语言的三大特征之一
1、概念
什么是多态?顾名思义,同一种事物,在不同的时刻表现不同的状态。
多态也称之为向上转型,将子类类型转为父类类型。就是用父类的引用变量(指向)执行子类的对象。前提是必须要有继承关系。即可形成多态。
2、特点
用父类类型表示任意子类类型对象,利于程序的扩展。
强制转换:将大类型转为小类型(前提:有继承关系)
Animal dog = new Dog();
Dog d = (Dog) dog;
构成多态 两个不同的时间段: 1、编译期:即写代码时 使用的类型是Animal(父类类型) 2、运行期:运行代码时 使用的类型是具体的子类类型成员方法:编译看左边,运行看右边。 静态方法:编译和运行都看左边。 成员变量:编译和运行都看左边。
以动物中的狗和猫举例:
//动物类
public class Animal {
int num=10;
public void eat(){
System.out.println("吃饭");
}
static void show(){
System.out.println("Animal");
}
}
//狗继承动物
public class Dog extends Animal {
public void eat(){
System.out.println("狗吃肉");
}
//子类中特有的方法
public void lookHome(){
System.out.println("狗看家");
}
static void show(){
System.out.println("Dog");
}
}
//猫继承动物
public class Cat extends Animal {
public void eat(){
System.out.println("猫吃鱼");
}
}
public class Test {
public static void main(String[] args) {
//多态
Animal dog = new Dog();
Animal cat = new Cat();
dog.eat();//结果:狗吃肉
//调用的是静态成员方法,编译时和运行时都看最左边的变量
dog.show();//结果:Animal
cat.show();//结果:Animal
//如果想要调用子类中的方法,将之强制转换,就可调用子类中的方法
Dog d = (Dog) dog;
d.show();//结果:Dog
//如果调用的是成员变量:那么编译和运行时都看左边
System.out.println(dog.num);//10
System.out.println(d.num);//10因为继承
}
}
3、instanceof关键字
向下转型时,父类引用仅能访问父类所声明的属性和方法,不能访问子类独有的属性和方法。
这时候如果调用子类中的特有方法,系统将会提示/ClassCastException/错误。
当出现ClassCastException错误时 (使用instanceof判断:父类类型中持有的实际类型是否是指定的类型) public void putAnimal(Animal animal){ if(animal instanceof Dog) { //父类的类型与指定的类型相同,返回true,否则,就返回false } }
解决办法:
以把动物装进冰箱为例,
public class Bx {
//装动物
public void putAnimal(Animal animal){
System.out.println("把动物装进冰箱");
// 当出现ClassCastException错误时 (加instanceof判断 父类类型中持有的实际类型是否是指定的类型)
if(animal instanceof Dog) {//instanceof:表示父类类型中持有的实际类型是否是指定类型
//父类的类型与指定的类型相同,返回true,否则,就返回false
Dog dog = (Dog) animal;//向下强制转换
dog.lookHome();
}
}
public void putObject(Object obact){
System.out.println("把东西装进冰箱");
}
}
//狗继承动物
public class Dog extends Animal {
public void eat(){
System.out.println("狗吃肉");
}
//子类中特有的方法
public void lookHome(){
System.out.println("狗看家");
}
static void show(){
System.out.println("Dog");
}
}
public static void main(String[] args) {
Animal Dog1 = new Dog();
Dog1.eat();//狗吃肉
Bx bx = new Bx();
bx.putAnimal(Dog1);//结果:把动物装进冰箱 狗看家
bx.putAnimal(Cat);//结果:把动物装进冰箱 (不会执行其他语句)
bx.putObject(Dog1);//把东西装进冰箱
}
}
7、接口
1、概念
我们生活中的最常见的接口:USB接口
(USB接口本身没有实现任何功能,USB接口规定了数据传输的要求,可以被多种USB设备实现)
从本质上讲:接口是一种特殊的抽象类,这种抽象类中包含抽线方法。
接口中可以定义的内容: jdk8版本之后接口中可以定义:常量,抽象方法,静态方法,默认方法。 jdk8版本之前只能定义成员变量和抽象方法.
2、接口的定义和使用
接口的定义:使用 interface 关键字用来声明一个接口。
接口的使用:
类使用implements关键字实现接口。
在类声明中,Implements关键字放在class声明后面。
类实现接口后,要么重写接口中的所有抽象方法,要么将该类声明为抽象类。
一个类可以实现多个类,但只可以继承一个类。
特点:
接口可以继承接口,且接口可以继承多个接口。
接口是隐式抽象的,主要用来定义功能.
接口中可以定义静态常量,抽象方法,静态方法,默认方法.
接口不能实例化对象
接口是要被类实现,一个接口可以被多个实现
当类实现接口的时候,类要实现接口中所有的抽象方法,否则该类必须声明为抽象的类
接口与实现类之间存在多态性
//定义接口
public interface InterFace {
}
//接口继承多个接口
public interface A extends MyInterface,InterFace{
}
//类实现接口
public class Demo implements MyInterface,A,B {
//类实现接口后: 要么重写接口中的所有抽象方法,要么将该类声明为抽象类。
@Override
public void eat(){
}
}
//定义接口
public interface MyInterface {
int num=10;// 原型:public static final int num=10;常量
void eat();// 原型:public abstract void eat();
//静态方法 可以直接通过接口名直接去调用
public static void test(){
}
//默认方法 被子类继承后调用的
default void test1(){
}
}
public class Test {
public static void main(String[] args) {
System.out.println(MyInterface.num);
MyInterface.test();
}
}
持续更新中.....