encapsulation_Aperson
package com.oop._01encapsulation;
/**
* 面向对象的三大特征之封装:
* 1. 广义上的封装:定义方法是封装,定义类也是封装
* 2. 狭义上的封装:将类中属性封装
* 如何封装属性?
* --添加private访问权限修饰词,外界就不能直接访问属性了
* --然后提供属性有关的共有的getter和setter方法
*
*/
public class APerson {
//成员变量私有化
private String name;
private int age;
private char gender;
//无参构造器
public APerson()
{
System.out.println("无参构造器");
}
//全参构造器
public APerson(String name, int age, char gender)
{
this.name = name;
this.age = age;
this.gender = gender;
}
//为每个成员变量提供getter/setter方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
if(age<0||age>120)
{
System.out.println("年龄不合法");
return;
}
this.age = age;
}
public int getAge() {
return age;
}
public void setGender(char gender){
if(gender!='男'&&gender!='女')
{
// System.out.println("性别不合法");
//如果赋值有问题,可以使用下面的方式让程序中断,并提示
throw new RuntimeException("性别不合法");
}
this.gender = gender;
}
public char getGender() {
return gender;
}
}
encapsulation_APersonTest
package com.oop._01encapsulation;
/**
* 属性的封装调用
*/
public class APersonTest {
public static void main(String[] args) {
//创建对象
APerson p1 = new APerson();
//p1.name = "小明"; name 私有化了,不可以直接访问
//调用公有方法访问
p1.setName("小明");
p1.setAge(17);
p1.setGender('女');
//System.out.println(p1.name); 也不能直接访问,需要调用公有的方法
System.out.println(p1.getName());
System.out.println(p1.getAge());
System.out.println(p1.getGender());
p1.setGender('m');
System.out.println(p1.getGender());
}
}
encapsulation_BSingleton
package com.oop._01encapsulation;
/**
* 单例模式的饿汉模式:
* 1. 提供一个该类的,私有的,静态的属性,并在静态代码块里赋值
* 2. 提供一个私有的构造器,避免外界直接调用构造器
* 3. 提供一个共有的,静态的方法,来获取当前类的对象
*/
public class BSingleton {
private static BSingleton instance;// instance 实例的含义 1usage
static{
instance = new BSingleton();
}
// 构造器私有化
private BSingleton(){}
public static BSingleton getInstance(){
return instance;
}
}
encapsulation_BSingletonTest
package com.oop._01encapsulation;
public class BSingletonTest {
public static void main(String[] args) {
//看是否能直接创建
// BSingleton bsingleton = new BSingleton(); 构造器私有化,不能直接调用
//看是否能直接访问成员
// BSingleton.getInstance; 成员私有化了,不能直接访问
//只能使用下面的方式获取该类的具体实例
BSingleton bsingleton = BSingleton.getInstance();
//再获取一次
BSingleton bsingleton2 = BSingleton.getInstance();
/**
* == :双等号,比较的是两个对象的地址
*/
System.out.println(bsingleton == bsingleton2);
}
}
encapsulation_Csingleton
package com.oop._01encapsulation;
/**
* 单例模式的懒汉模式:
* 1. 提供一个该类的,私有的,静态的属性
* 2. 提供一个私有的构造器,避免外界直接调用构造器
* 3. 提供一个公有的,静态的方法,来创建当前类的对象。如果不存在,说明未创建
* 4. 懒汉模式,有线程安全隐患,比如两次调用都恰好执行到判断等于null,
* 都会执行创建实例那一行的代码,会创建两个对象
*/
public class CSingleton {
//私有化的静态变量
private static CSingleton instance;
//私有化构造器
private CSingleton(){}
//提供一个公有的,静态的方法,来创建当前类的对象。
public static CSingleton getInstance(){
//如果不存在,说明未创建
if(instance == null){
//创建对象,将地址存入静态变量
instance = new CSingleton();
}
//返回对象的地址,之前有就用之前的,没有就用新的
return instance;
}
}
encapsulation_CsingletonTest
package com.oop._01encapsulation;
public class CSingletonTest {
public static void main(String[] args) {
//获取两次该类型的对象
CSingleton singleton1 = CSingleton.getInstance();
CSingleton singleton2 = CSingleton.getInstance();
//双等号判断地址
System.out.println(singleton1 == singleton2);
}
}
extend_APerson
package com.oop._02extend;
/**
*
*/
public class APerson {
private String name;
private int age;
private char gender;
public APerson(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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 char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
extend_Cat
package com.oop._02extend;
/**
* final修饰词的讲解:
* 1. 修饰类,表示该类不能再有子类,即不能被继承了
* 2. 修饰成员变量: 只能初始化一次,不能被再次赋值
* 3. 修饰方法: 表示该方法不能再被重写了。
* 4. 修饰局部变量
*/
//public final class Cat {
public class Cat {
private final String name;
public Cat(String name) {
this.name = name;
}
public final int sum(int a, int b){
//测试final修饰局部变量
final int x;
x = 100;
// x = 101, final修饰的变量不能再次赋值
return a+b;
}
// 下面的方法给name赋值,已经不是初始化了。
// 因为想要执行该方法,那么构造器一定先执行了
// public void setName(String name) {
// this.name=name;
// }
}
//不能继承Cat 因为Cat是final修饰的
//class Acat extends Cat {}
//研究父类里的方法被final修饰,是否还能重写
class BCat extends Cat {
public BCat(String name) {
super(name);
}
// public int sum(int a, int b){
// return a+b;
// }
}
extend_MyUtil
package com.oop._02extend;
/**
* static修饰词
* 1. 修饰成员变量:
* 静态成员变量,属于类的,公共资源,使用类名,调用
* 注意:可以使用引用变量‘.’调用,但是不合理,因为不属于对象
* 2. 修饰方法:
* 静态方法:属于类的,公共资源,使用类名,调用
* 注意:可以使用引用变量‘.’调用,但是不合理,因为不属于对象
* 静态方法不能直接访问非静态成员变量
* static方法 不能被重写,但是子类可以提供和父类可以一样的静态方法,各是各的。
* 3. 修饰代码块:
* 静态代码块,类加载时只执行一次,通常用于加载静态资源:图片、视频等
* 4. 修饰类
* 可以修饰内部类
*/
public class MyUtil {
private String name;
//定义一个水桶的容量,定义是升L
public static int contain = 18;
//如果想要达到每时每刻看到的静态资源是一样的,那么就应该用final修饰,即常量
public static final double PI = 3.14; //static和final的顺序不固定
public static void sum( int a, int b) {
// 不能直接访问非静态成员
// this.name="小明";
// addContain();
contain = 19;
}
public void addContain() {
this.contain++;
}
public void subContain() {
this.contain--;
}
public static void main(String[] args){
MyUtil p1 = new MyUtil();
//查看容量
System.out.println(MyUtil.contain);
p1.addContain();
MyUtil p2 = new MyUtil();
//注意,静态变量,使用类名调用
System.out.println(MyUtil.contain);
p2.subContain();
}
}
class sub extends MyUtil{
// @Override 添加注解后报错 因为static方法 不能被重写
// 但是子类可以提供和父类可以一样的静态方法,各是各的。
public static void sum( int a, int b) {
// 不能直接访问非静态成员
// this.name="小明";
// addContain();
contain = 19;
}
}
extend_Student
package com.oop._02extend;
/**
* 定义一个学生类型,有人的特征,可以继承
* 有自己独有的特征:
* 学号: studentId
* 班级编号: classNo
*
* 在这里主要研究一下构造器:
* 1. 子类不能继承父类的构造器
* 2. 子类的构造器中可以使用super(有参传参)进行显式的调用父类中的某一个构造器
* 3. super(有参传参)和this(有参传参)一样,必须放在首行首列,因此不能共存
* 4. 子类的构造器中至少存在一个构造器调用了父类的构造器
* 5. 为什么至少要有一个调用父类的构造器: 因为子类继承过来的属性需要初始化
*/
public class Student extends APerson{
private String studentId;
private String classNo;
public String getClassNo() {
return classNo;
}
public void setClassNo(String classNo) {
this.classNo = classNo;
}
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
//添加自己的构造器
public Student(String studentId, String classNo){
super( "小心", 20, '女');
this.studentId = studentId;
this.classNo = classNo;
}
//重载一个构造器
public Student(String name, int age, char gender, String studentId, String classNo){
//this.name; 父类里的name属性私有化,虽然于类继承了,但是不能直接访问
//setName方法是继承来的,并且公有,可以直接使用
this( studentId, classNo);
setName(name);
setAge(age);
setGender(gender);
// this.studentId = studentId;
// this.classNo = classNo;
}
//添加toString方法 用来显示对象的属性值
public String toString() {
return "studentId='" + studentId +
", classNo='" + classNo +
", name='" + getName() +
", age=" + getAge() +
", gender=" + getGender();
}
}
extend_StudentTest
package com.oop._02extend;
public class StudentTest {
public static void main(String[] args) {
//调用子类五个参数构造器
Student xiaoming = new Student("张三", 18, '男', "2019001", "1班");
// System.out.println(xiaoming.getName());
// System.out.println(xiaoming.getAge());
// System.out.println(xiaoming.getGender());
// System.out.println(xiaoming.getStudentId());
// System.out.println( xiaoming.getClassNo());
System.out.println(xiaoming);
Student xiaoxin = new Student( "2019002", "2班");
System.out.println(xiaoxin);
}
}
extend_TDog
package com.oop._02extend;
/**
* 演示 继承中的方法的重写特点
*
* TDog是Animal的子类型,
*/
public class TDog extends Animal {
public static void main(String[] args) {
//创建一个子类对象
TDog dog = new TDog();
//调用继承过来的并且有访问权限的方法
dog.sport();
}
//子类独有的功能
// @Override 注解只能放在子类重写父类方法的上面,用于检测是否是重写,不是则报错
public void noise() {
System.out.println("汪汪汪");
}
// 与父类完全一致也算是重写
@Override
public void sport() {
System.out.println("运动中");
}
//子类在重写父类的方法时,返回值类型与父类中的方法可以相同,也可以是其子类型:TDog就是Animal的子类型
public TDog getMyClass() {
return null;
}
//子类在重写父类的方法时,访问权限应该大于等于父类方法的访问权限(你的拳不够快也不够狠!)
public String showInfo() {
return null;
}
//自己独有的方法
public String showInfo( int a) {
return null;
}
}
//动物类型
class Animal {
private String color;
//公有的,返回值类型void
public void sport() {
System.out.println("运动中");
}
//公有的,返回值类型Animal
public Animal getMyClass() {
return null;
}
//默认的,返回值类型String
String showInfo() {
return null;
}
}
extend_Teacher
package com.oop._02extend;
import java.lang.reflect.Field;
/**
* 定义一个Teacher类型,父类是Object
*/
public class Teacher {
private String name;
private int age;
private char gender;
//无参构造器
public Teacher() {
}
//全参构造器
public Teacher(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/**
* 重写eqyals方法
* 1. 判断传入的是不是null
* 2. 判断传入的是不是自己
* 3. 判断传入的是不是同类型,如果是就转成同类型比较
* 4. 其他任何情况都返回false;
*/
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof Teacher) {
Teacher t = (Teacher) obj;
return this.name.equals(t.name)
&& this.age == t.age
&& this.gender == t.gender;
}
return false;
}
/*
toString()的作用,用于将对象的属性信息拼接起来,返回字符串
这样就可以查看每个对象的样子了。
但是Object类中的toString()方法,返回的是类的全名+@+hashCode值的16进制
对我们没有太大意义,因此自定义类型是,通常都要重写
而且,该方法在输入语句中,会自动调用。
*/
@Override
public String toString() {
return "Teacher{" + "name='" + name + '\'' + ", age=" + age + ", gender=" + gender + '}';
}
public static void main(String[] args) {
Teacher teacher = new Teacher();
System.out.println(teacher);
//创建两个teacher
Teacher t1 = new Teacher("张三", 18, '男');
Teacher t2 = new Teacher("张三", 18, '男');
System.out.println(t1 == t2); //比较地址 返回false
boolean r = t1.equals(t2); //比较两个对象的属性是否相同
System.out.println(r); //true
//通过对象调用getClass(),来获取Teacher对应的描述类的对象
Class<? extends Teacher> aClass =t1.getClass();
System.out.println(aClass.getName());
//获取类里的所有属性 Field字段的含义
Field[] fields =aClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
polymorphism_Animal
package com.oop._03polymorphism;
public class Animal {
private String color;
private String name;
private int age;
public Animal() {}
public Animal(String color, String name, int age){
this.color = color;
this.name = name;
this.age = age;
}
//动物都会有发出声音的行为
public void noise(){
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
public Dog(String color, String name, int age) {
super(color, name, age);
}
public void noise(){
System.out.println("汪汪汪");
}
public void lookHouse(){
System.out.println("看家");
}
}
class Cat extends Animal {
public Cat(String color, String name, int age) {
super(color, name, age);
}
public void noise(){
System.out.println("喵喵喵");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
polymorphism_AnimalTest
package com.oop._03polymorphism;
/**
* 面向对象的三大特征之多态: 一个对象的多种形态。
* 面试时可以多加一种:方法的多态(重载和重写)
* 第一种: 向上造型(向上转型)
* - 父类型的变量,引入子类型的对象
*
*
*/
public class AnimalTest {
public static void main(String[] args) {
//使用Animal声明一个变量,引用一个Cat对象
Animal a = new Cat("白色", "小花", 3);
//调用方法:
a.noise();//编译期间不会出现问题,因为父类里面有该方法。运行期间,执行的人对象的类型里的方法逻辑
// a.getMouse(); 调用不到该方法,因为a这个变量类型里没有该方法(编译期间,看变量类型)
test1(a);
Dog dog = new Dog("黑色", "大黑", 8);
test1(dog);
}
//测试: 执行动物的叫声 这就是向上造型的优势所在,
// 父类型的变量作为参数,更加灵活,可以传入不同的子类型对象
public static void test1(Animal aminal) {
aminal.noise();
}
}
polymorphism_AnimalTest2
package com.oop._03polymorphism;
/**
* 多态的另外一种形式: 向下转型。
* 父类型的变量赋值给子类型的变量,需要强制转换
* 该操作可能会出现失败,失败的话,就会报异常:ClassCastException 类造型异常
* 如果想要避免失败,可以使用instanceof 关键字来进行判断:
* 该变量指向的对象是否属于某一个类型。如果是,返回true,否则返回false
*
* 应用场景:
* 多数情况下,定义方法时,形参都是父类型的变量,原因是可以接受任意子类型的对象
* 但是有的时候,在这样的方法里的逻辑中,
* 可能会用到该对象的独有功能,因此会涉及到向下转型
*/
public class AnimalTest2 {
public static void main(String[] args) {
//创建一个父类型的变量引用子类型的对象
Animal an = new Dog("black", "小黑", 3);
an.noise();
//调用一下对象的独有功能//am.LookHouse();
// 编译期间看变量类型。没有该方法,所以报
// 只能向下转型才可以
Dog d = (Dog)an;
d.lookHouse();
//上述代码没有问题,但在真正编程时,有可能写成如下代码:
//编译期间,不报错,但是运行期间,就会报异常。
// Cat c = (Cat)an;
// c.catchMouse();
//避免上述情况发生,使用instanceof即可
if (an instanceof Cat) { //因为an指向的是一个Dog对象,因此进不去分支
//避免了报错
Cat c = (Cat)an;
c. catchMouse();
}
}
}