封装:
不让外界直接访问成员变量,所以要让成员变量私有化 但是必须要为外界提供可以访问的方法(目的是为了获取和赋值) 所以要为私有属性提供两个公共的方法,一个用来赋值(set),一个用来获取值(get)
public class Person {
private String name;
private int age;
public Person() {
}
//无参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
if (name != null && name.length() < 5) {
this.name = name;
}
}
public String getName() {
return this.name;
}
public void setAge(int age) {
if (age > 0 && age < 100) {
this.age = age;
}
}
public int getAge() {
return age;
}
}
接下来用一个简单的初始单例模式举例
public class Window {
/*
此处用到的是一个简化的初始单例模式(解决一类问题的算法)
*/
private static Window window = null;//定义仅有一个的静态成员
private Window(){
}
//构造方法私有化,外界无法访问,无法创建新对象
/*
构造方法私有化,外接无法访问
外界还是需要这个对象
所以在类的内部提供一个公开的方法可以用来获取创建的唯一对象
*/
public static Window getWindow() {
//如果window值与初始创建的值不一样,那就执行if语句创建一个新对象
if (window != null) {
window = new Window();
}
return window;//如果不为空,那不执行if语句,直接返回已经有了值的window,借此达到只有一个新对象的目的
}
}
public class TestWindow {
public static void main(String[] args) {
// new Window();
System.out.println(Window.getWindow());
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setName("石昊");
System.out.println(p.getName());
p.setAge(20);
System.out.println(p.getAge());
}
}
继承
在Java中,一个类只能继承一个类,而且类与类之间存在一定逻辑联系,比如动物中包括狗,猫,鸟,其中动物是父类,狗猫鸟是子类
继承通过extends关键字来实现
注意:
当父类中存在抽象方法时,父类就是抽象类
此时子类中必须有具体的实现方法(方法重写)
或者子类也变为抽象类,让子类的子类去实现父类中的抽象方法
这是父类
public abstract class Animal extends Object{
String name;
public Animal(){
super();//调用父类(Object)构造方法
System.out.println("Animal无参构造方法");
}
public abstract void eat();//抽象方法,没必要具体实现功能,因为子类与父类在此功能实现时具体方法有所不同
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是子类
package day2.jc;
//这是子类(派生类),继承父类Animal中的非私有属性和方法
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
//public abstract class Dog extends Animal{ 当继承的父类为抽象类时,可以选择将当前类也定义为抽象类
//子类可以扩展自己的功能,不影响其他类
private String type;
public Dog(){
super();//调用父类构造方法
System.out.println("Dog无参构造方法");
}
public Dog(String name){
System.out.println("Dog有参构造方法");
}
@Override
//当继承的父类为抽象类时,也可以选择重写抽象类(父类)中的抽象方法
public void eat() {
System.out.println("狗吃骨头");
}
public void bizi(){
System.out.println("鼻子很灵");
}
public void pihao(){
System.out.println("会吃粑粑");
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
接下来是测试代码
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("胜广");
dog.getName();
System.out.println(dog.getName()+"是狗狗");
Cat cat = new Cat();
cat.setName("佳宇");
cat.getName();
System.out.println(cat.getName()+"是猫猫");
dog.eat();
cat.eat();
}
}
注意,方法重写的条件:
类中方法无法满足子类需求,所以重写,会覆盖父类(优先调用子类本身定义的重写方法) 结构相同,
方法名一致 参数一致 返回值一致 子类重写时,方法访问权限必须大于等于父类的方法访问权限
构造方法,静态方法不能重写 成员方法不存在重写
注意!此处只是本人恶趣味,舔狗只是一个小玩笑,不要在意!
package day2.jc;
/*
多重继承,可以继承父类,也可以继承父类的父类
传递性
*/
public class TianGou extends Dog{
public TianGou(){
//super();//调用父类构造方法,默认存在,必须放在构造方法第一行
super();
System.out.println("舔狗无参构造方法");
//使用super访问父类中的那部分成员
//super()指的是调用父类中的构造方法
super.name="";
}
public void tian(){
System.out.println("舔狗会舔");
}
public void bizi(){
//方法重写,父类中方法无法满足子类需求,所以重写,会覆盖父类(优先调用子类本身定义的重写方法) 结构相同,
/*
方法名一致
参数一致
返回值一致
子类重写时,方法访问权限必须大于等于父类的方法访问权限
构造方法,静态方法不能重写
成员方法不存在重写
*/
System.out.println("鼻子超级无敌灵");
}
}
顺便讲一下super关键字
调用父类构造方法,默认存在,必须放在构造方法第一行 使用super访问父类中的那部分成员 super()指的是调用父类中的构造方法
package day2.jc;
public class TestTianGou {
/*
Animal无参构造方法
Dog无参构造方法
舔狗无参构造方法
这三个是运行结果顺序,下方为注解
在创建子类对象时,父类的无参构造方法也会被调用,且优先于子类本身的构造方法执行
父>子
在创建完子类对象后,有可能直接访问父类中的成员,所以父类的构造方法优先于子类的构造方法执行
super并不是表示父类对象!!!!!
在创建子类对象是,并不会创建父类对象,只是将父类中的成员加载到子类对象内存空间中
确保父类中的成员被初始化
*/
public static void main(String[] args) {
TianGou tianGou = new TianGou();
tianGou.setName("舔狗");
tianGou.getName();
System.out.println(tianGou.getName());
tianGou.bizi();//Dog类
tianGou.pihao();//Dog类
tianGou.eat();//Animal类
tianGou.tian();//自己本身的类
}
}
多态
多态:一个事物在不同时刻表现出来的不同状态 父类在不同时刻表现为不同的子类对象
多态的条件: 1.类与类之间必须有继承关系 2.必须有方法重写 3.父类的引用 指向 子类的对象
多态的优点: 可以用一个父类表示任意子类,向上转型 极大丰富了程序灵活的扩展性
多态的缺点: 就是当需要调用子类中的特有功能时, 编译只看左边,导致无法调用 那此时就需要向下转换(强制)同时要进行判断(instanceof) 此时判断所持有的对象是否是所需要的类型
Animal为父类,Dog Cat Bird为子类
public abstract class Animal {
String name;
public abstract void eat();//抽象方法,没必要具体实现功能,因为子类与父类在此功能实现时具体方法有所不同
public void show(){
System.out.println("出现");
}
public class Dog extends Animal {
@Override
//当继承的父类为抽象类时,也可以选择重写抽象类(父类)中的抽象方法
public void eat() {
System.out.println("狗吃骨头");
}
public void lookHome(){
System.out.println("狗可以看家");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void buzhuo(){
System.out.println("猫会抓老鼠");
}
}
public class Person {
public void feedAnimal(Animal animal){
animal.eat();
}
public void feedObject(Object object){
}
}
package day2.dt;
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
dog.eat();
dog.show();
dog.name = "狗";
System.out.println(dog.name);
/*多态的缺点就是当需要调用子类中的特有功能时,
编译只看左边,导致无法调用
那此时就需要向下转换(强制)同时要进行判断(instanceof)
此时判断所持有的对象是否是所需要的类型
*/
if (dog instanceof Dog){
Dog d =(Dog)dog;
d.lookHome();
}
Animal cat = new Cat();
cat.eat();
cat.show();
cat.name = "猫";
System.out.println(cat.name);
if (cat instanceof Cat){
Cat c = (Cat)cat;
c.buzhuo();
}
Animal bird = new Bird();
bird.eat();
bird.show();
bird.name = "鸟";
System.out.println(bird.name);
if (bird instanceof Bird){
Bird b = (Bird)bird;
b.chuhai();
}
/*
Animal dog
dog.eat();
在编译期间 调用的是Animal中的eat()
在运行期间 dog实际指向的是一个具体的Dog类对象,所以调用的是Dog中的eat()
对非静态的成员方法
编译看左边 , 运行看右边
对静态的成员方法
编译看左边 , 运行也是看左边
对成员变量
编译看左边 , 运行也是看左边
*/
Person p = new Person();
p.feedAnimal(dog);
p.feedAnimal(cat);
p.feedAnimal(bird);
}
}