三大特性
一、封装
- 程序设计追求 “高内聚,低耦合”
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅暴露少量的方法给外部使用。
- 封装(就是数据的隐藏)
- 通常禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
- 重点: 属性私有, get / set
1.基本演示:
首先创建了一个学生类
package com.oop;
public class Student {
//封装大多时候针对属性,较少对方法用
//名字
private String name ;
//学号
private int id ;
//性别
private char sex;
//属性已私有
//get/set 可以提供一些可以操作这个属性的方法
//get可以获得这个数据 set 可以设置值
public String getName(){
return this.name;
}
public void setName(String name){
this.name=name ;
}
//自动生成get/set的快捷键(alt + insert)
//演示
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
之后在主类中去调用被保护的数据(private)
public class Application {
public Application() {
}
public static void main(String[] args) {
Student s1 = new Student();
// 设置名字
s1.setName("xiangliang");
System.out.println(s1.getName());
// 设置学号
s1.setId(69518541);
System.out.println(s1.getId());
}
}
2.探究:
创建了一个Studen01类
package com.oop;
public class Student01 {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age>102||age<0){//这里设置了年龄上限下限
System.out.println("keke please sit down");
this.age=3;//乱输入就是3岁小孩喽
}
else {
this.age = age;
}
}
}
主类中创建对象并测试
package com;
import com.oop.Student;
import com.oop.Student01;
import java.util.Scanner;
public class Application {
public Application() {
}
public static void main(String[] args) {
Student s1 = new Student();
// 设置名字
s1.setName("xiangliang");
System.out.println(s1.getName());
// 设置学号
s1.setId(69518541);
System.out.println(s1.getId());
System.out.println("======================");
//接下来探究下封装的实际作用
Student01 xiaohong = new Student01();//开辟空间
Scanner scanner = new Scanner(System.in);//使用交互
xiaohong.setAge(scanner.nextInt());//用户输入
System.out.println(xiaohong.getAge());//打印结果
scanner.close();//关闭控制台
}
}
结果1:
结果2:
3.总结
- 封装可以提高程序的安全性保护数据
- 隐藏代码的实现细节
- 统一接口
- 提高系统的可维护性
- 一定要记住 属性私有(private) get/set
二、继承
- extands的意思是“扩展”派生类是超类的扩展
- 继承本质是对某一批类的抽象
- java中的类只有单继承而无多继承!!
- 继承是类和类之间的一种关系。此外还有其他关系(依赖、组合、聚合)
- 具有继承关系的两个类,其一为:派生类;其二为:基类
- public class 派生类 extends 基类{}
- 两个类之间意义上具有 “is a”关系
- ======================================
- 重点
- Object
- super
- 方法重写
1.实例演示
创建基类Person
package com.jicheng;
//创建了一个 人 类
public class Person {
/*几种修饰符
public公共的
protected受保护的
default默认的(不写修饰符时默认为default)
private私有的
*/
//继承方法时一般用public
//属性一般设为私有private
int jinbi = 100;//default
private int qian = 100000000;//private
public long chaifu =100000000000000000L;//public
public static void say() {
System.out.println("TanLanHeiAn");
System.out.println("??????????????????");
}
//私有的属性可以留一些公共的方法供派生类去调用
public int getQian() {
return qian;
}
public void setQian(int qian) {
this.qian = qian;
}
}
创建派生类Student(注意该类中我未放入代码)其继承于Person类
package com.jicheng;
//创建了一个 学生 类
// 人 类 包含 学生 类
//使学生类继承人类(extends继承)
public class Student extends Person{
}
创建一个运行程序的主类Application01
package com;
import com.jicheng.Student;
public class Application01 {
public static void main(String[] args) {
Student XiaoHei = new Student();//创建了一个学生对象小黑
XiaoHei.say();//调用一下对象小黑所归属的学生类的基类(人类)的方法say()----------成功了。所以学生类里面虽然没东西,但是继承了人类的方法所以学生类也有say方法,只是我们看不到。
System.out.println(XiaoHei.chaifu);//打印一下对象小黑所归属的学生类的基类(人类)的数据chaifu财富----------成功了。
// System.out.println(XiaoHei.qian);//失败了-------无法直接调用(qian被我设置为private)
System.out.println(XiaoHei.getQian());//成功了--------我给private的qian提供了方法getQian和setQian
}
}
简单运行一下
2.查看继承关系
使用快捷键ctry+H
3.Object
- 在java中所有的类都默认直接或间接继承Object类
- Object的位置在java.lang
4.surper
示例:
package com.jicheng01
class Person02 {
//创建一个无参构造器
public Person02() {
println "Person`s wucan"//Person的无参
}
//基类中定义了一个受保护的属性name
protected String name ="00000001";
public void print(){//定义了一个打印Person公共方法print
System.out.println("Person");
}
}
package com.jicheng01;
public class Student02 extends Person02{
//构造器
public Student02(){
System.out.println("Student02`s wucan");//Student02的无参
}
private String name = "00000002";//私有属性
public void print(){//定义了打印”学生“的方法print
System.out.println("Student");
}
public void test1(){//调用3个方法进行比较
print();
this.print();
super.print();
}
public void test(String name){//调用三个属性进行比较
System.out.println(name);
System.out.println(this.name);//this调用了当前类属性
System.out.println(super.name);//super调用了基类属性
}
}
package com;
import com.jicheng01.Student02;
public class Appplication02 {
public static void main(String[] args) {
Student02 student02 = new Student02();
student02.test("000000003");//调用三个属性进行比较
student02.test1();//调用3个方法进行比较
}
}
结果:
结论:
-
super的注意事项
- super若想调用基类的构造方法,位置必须在构造方法的第一个
- super只能出现在派生类的方法或构造方法中
- super和this不能同时调用构造方法
另外
this调用自身
super是对基类的引用 -
在子类的构造方法中
编译器会自动在子类构造函数的第一句加上 super(); 来调用父类的无参构造器;此时可以省略不写。如果想写上的话必须在子类构造函数的第一句,可以通过super来调用父类其他重载的构造方法,只要相应的把参数传过去就好。 因此,super的作用主要在下面三种情况下: - 调用父类被子类重写的方法; - 调用父类被子类重定义的字段(被隐藏的成员变量); - 调用父类的构造方法;其他情况,由于子类自动继承了父类相应属性方法,关键字super可以不显示写出来。
5.方法的重写
- 重写只针对方法,和属性无关
代码一组:
package chongxie.Deom.ChongXie01;
//重写只针对方法,和属性无关
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
package chongxie.Deom.ChongXie01;
public class A extends B{
public static void test(){
System.out.println("A=>test()");
}
}
package chongxie.Deom;
import chongxie.Deom.ChongXie01.A;
import chongxie.Deom.ChongXie01.B;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边的数据类型有关
A a = new A();
a.test();
//基类的引用指向派生类
B b = new A();
b.test();
}
}
结果:
组二:
(我去掉一个static后会报错。。无论是基类还是派生类)同时去掉2个static不会报错。
之后我将其注释,加入新的重写
组三 重写方法的代码
package chongxie.Deom.ChongXie01;
//重写只针对方法,和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
package chongxie.Deom.ChongXie01;
public class A extends B{
// public void test(){
// System.out.println("A=>test()");
// }
//Override翻译:(函数覆盖;复盖;覆盖;重写;重载)
@Override//自动生成的注解(有功能的注释)
public void test() {
// super.test();//其默认调用的父类方法(我们可以去写自己的方法)
System.out.println("A=>test()");
}
}
package chongxie.Deom;
import chongxie.Deom.ChongXie01.A;
import chongxie.Deom.ChongXie01.B;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边的数据类型有关
A a = new A();
a.test();
//基类的引用指向派生类
B b = new A();
b.test();
}
}
我的Application类未做任何更改。。。接下来看看运行结果
思考与总结:
-
方法静态与非静态有巨大区别
-
派生类可以重写基类的方法(重写与非静态有关)
-
重写需要有public关键词,使用private关键词无法重写
-
方法重载在本身类中实现,方法重写在继承类中实现。
-
实现重写时注意点:
- 方法名相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不可缩小 (public>protected>default>private)
- 抛出的异常:范围可以缩小但不可扩大(ClassNotFoundExcepsion)
- 派生类和基类的方法要一致;而方法体不同。
-
为什么需要重写:
基类的功能 派生类不一定需要 或 不一定满足
三、多态
概念:
方法的重写、重载与动态连接构成多态性
目的:(Java之所以引入多态的概念,原因之一就它在类的继承上的问题和C++不同,后者允许多继承,这确实给其带来了非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,势必在功能上有很大的限制,所以,Java引入多态性的概念以弥补这点不足,此外,抽象类和接口也是解决单继承规定限制的重要手段.同时,多态也是面向对象编程的精髓所在.)
特性:
-
同一个方法可以根据发送的对象不同而采用多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多
-
多态存在的条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
-
注意点:
-
方法有多态
-
属性无多态
-
-
instanceof
1.试验探究演示一:
父类:
package com01.duotai.deomo;
public class Person {
public void say(){
System.out.println("ShuoHua");//说话
}
}
子类:
package com01.duotai.deomo;
public class Student extends Person{
public void say(){
System.out.println("ChangGe");//唱歌
}
}
主类:
package com01.duotai;
import com01.duotai.deomo.Person;
import com01.duotai.deomo.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
// new Student();//学生类
// new Person();//人类
//但可以指向的引用类型却不一定确定(父类的引用可以指向子类)
Student xiaoliang = new Student();//创建对象:小亮。类型:Student。
Person xiaohei = new Student();//创建对象:小黑。类型:Student。
Object xiaoqing = new Student();//创建对象:小青。类型Student。
xiaoliang.say();
xiaohei.say();
// xiaoqing.say();
}
}
结果
思考:为什么xiaohei的引用类是Person类(父类)但会调用子类的重写方法?(注意:这些对象全由new Student创建)什么是父类引用?
2.试验探究演示二:
还以Person为父类,创建子类Oldman
package com01.duotai.deomo;
public class Oldman extends Person{
public void say1(){
System.out.println("Tanqi");//叹气
}
}
主类去调用
package com01.duotai;
import com01.duotai.deomo.Oldman;
import com01.duotai.deomo.Person;
import com01.duotai.deomo.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
// new Student();
// new Person();
//但可以指向的引用类型却不一定确定(父类的引用可以指向子类)
Student xiaoliang = new Student();//创建对象:小亮。引用类型:Student。
Person xiaohei = new Student();//创建对象:小黑。引用类型:Person。
Object xiaoqing = new Student();//创建对象:小青。引用类型Object。
xiaoliang.say();//say方法被重写,所以执行子类方法say。
xiaohei.say();//同样执行子类方法say
// xiaoqing.say();会报错。。。不可以这么写
Oldman old1 = new Oldman();//创建对象:old1。引用类型:Oldman。
Person old2 = new Oldman();//创建对象:old2。引用类型:Person。
old1.say1();
// old2.say1();//old2无法调用子类Oldman的方法say1()
}
}
结果:
old2.say1();根本无法被创建,毕竟Person中都没写say1方法
可以发现一些规律:
1. 若:父类有方法A(){b},子类无方法,主类中创建一个子类型对象; 则:主类可以调用子类继承父类所得的方法A(){b}
2. 若:父类有方法A(){b},子类有方法A(){c},主类中创建一个子类型对象; 则:主类可以调用子类重写父类方法A(){b}所得的方法A(){c}
3. 若:父类无方法,子类有方法A(){b},主类中创建一个父类型对象; 则:主类不可以调用子类的独有方法A(){b}。
重点:
4. 若:父类有方法A(){b},子类有方法A(){c},主类中创建一个引用父类型指向子类型对象; 则:主类可以调用子类重写父类方法A(){b}所得的方法A(){c} 即所谓:动态链接
根据我的理解:
我们可以创建一主类,一父类,多子类。父类中提前写好一些基本的属性和方法,然后子类可以继承父类的属性和方法;并且子类中可以有一些自己独有的属性和方法使其功能更强大,而在实例化不同子类对象时,提前有多个不同子类可以对同一个父类的同一个方法进行重写,使得对象调用方法时更加灵活。