先定义一个Person类:
public class Person {
String name;
int age;
public void eat(){
System.out.println("人要吃饭");
}
public void sleep(){
System.out.println("人要睡觉");
}
}
再编写Person Test类:
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "Tom";
p1.age = 21;
p1.eat();
p1.sleep();
System.out.println(p1.name);
System.out.println(p1.age);
}
}
用对象P1.XXX的方式调用Person类里的方法或属性
有四个权限修饰关键字,由大到小分别为: public 、protected 、缺省 (默认)、private
像String name; int age; 前面没有修饰的就为默认权限
一般来说,我们不希望对象直接访问类中的属性,因此都将属性私有化,而通过公共的get 、set 方法提供一个接口来访问修改这些属性
public class Person {
private String name;
private int age;
public void eat(){
System.out.println("人要吃饭");
}
public void sleep(){
System.out.println("人要睡觉");
}
}
私有化属性后,测试类中的name和age会报错,因为Person类的name和age对外不暴露,需要提供方法
public void setAge(int a){ //设置年龄
age = a;
}
public int getAge(){ //获取年龄
return age;
}
引出:this关键字: 在set方法中,参数 a 有时候会忘记代表什么含义;起名字要做到见名知义
(如图,会在调用时提示该参数是什么,如果用a b c这些代替会乱)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VV4LKf3Z-1618241751880)(C:\Users\62561\AppData\Roaming\Typora\typora-user-images\image-20210412222448421.png)]
所以不妨把参数a改成age
但这样一来肯定会报错,所以需要在前面的age前加上 this. :表示“当前对象的”含义
再添加 set和get name方法:
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
这样一来,在测试类中虽然不能直接用 对象.属性来设置,但可以通过set和get方法达到同样的效果
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
p1.sleep();
p1.setAge(2);
System.out.println("年龄为"+p1.getAge()+"岁");
p1.setName("Tom");
System.out.println("姓名为"+p1.getName());
}
}
//在创建对象时出现的 Person()是什么呢?
Person p1 = new Person();
回到Person 类,如果我们每次创建一个对象后,都要对他的name 和 age 属性进行赋值,这样显得多余
所以我们希望创建的对象有一个默认值,例如每次new Person()后,他的age 就是4
这里就涉及到构造器:系统中会默认提供一个空参构造器,为
public Person(){ //尝试输入预设初始化值
age = 1;
}
如果我们在中间输入一些东西,那么每次创建对象后,他的age就都是1
what’s more,我们不想要每次创建完一个对象后都set他的属性,所以在构造方法中可以提前设置了他的初始化值,例如
public Person(String name,int age){
this.name = name;
this.age = age;
}
构造了一个有两个参数的构造器,那么在创建对象时,就可以尝试输入以初始化
Person p1 = new Person("Tom",20);
System.out.println("年龄为"+p1.getAge()+"岁"); //年龄为20岁
System.out.println("姓名为"+p1.getName()); //姓名为Tom
在引入继承性前,先了解 继承的概念
class B extends A{ // 称A为B的父类,B是子类
}
方法的重载:
如果在一个类中,写了两个同名但不同参的方法,那么这两个方法就构成了重载,例如:
public class Animal {
public void sleep(){
System.out.println("动物都要睡觉");
}
public void sleep(int hour){
System.out.println("它想睡"+hour+ "个小时");
}
}
而系统会根据后面的形参来自动使用具体哪个方法
方法的重写:
在他的子类中,写了一个同名同参的一个方法,那么这两个成为 “重写的方法” 和 “被重写的方法”:
public class Cat extends Animal{
public void sleep(){
System.out.println("我家的猫喜欢白天睡觉");
}
}
为什么要引入继承性?
public class Animal {
int age;
double weight;
public void sleep(){
System.out.println("动物都要睡觉");
}
public void sleep(int hour){
System.out.println("它想睡"+hour+ "个小时");
}
}
如果在类Animal中,定义了的属性和方法是通用的,如果创建一个Dog类,仍要重新copy一次这些属性和方法,代码显得冗余
所以用extends 关键字,继承了父类中所有的属性和方法
//例如,继承了Animal类后,新写入的方法则为 子类特有的方法
public class Dog extends Animal{
public void eat(){
System.out.println("狗喜欢吃骨头");
}
}
在测试类中
public class AnimalTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sleep(3); //它想睡3个小时
dog.sleep(); //动物都要睡觉
dog.eat(); //狗喜欢吃骨头
}
}
还是使用上面的例子,补充
public class Animal {
public void eat(){
System.out.println("动物都需要吃东西");
}
public void sleep(){
System.out.println("动物都要睡觉");
}
}
public class Cat extends Animal{
public void sleep(){
System.out.println("我家的猫喜欢白天睡觉");
}
public void eat(){
System.out.println("猫喜欢吃鱼");
}
public void shoot(){
System.out.println("喵喵喵");
}
}
public class Dog extends Animal{
public void sleep(){
System.out.println("我家的狗喜欢晚上睡觉");
}
public void eat(){
System.out.println("狗喜欢吃骨头");
}
public void watchdoor(){
System.out.println("狗可以看门");
}
}
补充了父类(动物)和他的两个子类(猫、狗) 可以看到sleep 和 eat 方法都是共有的,而子类将这两个方法进行了重写
而Cat类和Dog类分别多了一个父类没有的方法,下面进行测试:
public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Dog();
animal.sleep();
animal.eat();
//animal.watchdoor(); 编译不通过
}
}
需要注意的是, 虽然new了一个Dog(),但是他仍然是属于Animal类型,所以在调用方法时,需要用Animal类下的方法,
使用子类特有的方法时会报错
而多态性的使用,简化了代码,使得代码有了通用性,也隐隐透露出“接口”这种思想
在不使用多态性时,如果要用dog的sleep 和 eat 方法
public class AnimalTest {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.sleep();
d1.eat();
}
}
如果要用cat的sleep 和 eat 方法:
public class AnimalTest {
public static void main(String[] args) {
Cat d1 = new Cat();
d1.sleep();
d1.eat();
}
}
而如果使用多态性:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest t1 = new AnimalTest();
t1.test(new Cat()); //只需修改new 后面的类 看成是一个“入口”
}
public void test(Animal animal){ //看成是一个“接口”
animal.eat(); //传进去不同的类型,都有其对应的重写后了的方法,不用修改
animal.sleep();
}
}
这样一来,在编写代码量大的程序时,不必自己再找代码,而只需要修改这个“入口”,改好后不需要管
因为其都有对应重写了的方法,大大节约了修改的地方。