前言:菜鸟一枚,如有问题欢迎大家在评论区指出,我们一起学习。
1.8.1:静态关键字(static)
在类中声明的实例变量,其值是每一个对象独立的。但是有些成员变量的值不需要或不能每一个对象单独存储一份,即有些成员变量和当前类的对象无关。在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用和当前类的对象无关,那么创建对象就有点麻烦了。此时,就需要将和当前类的对象无关的成员变量、成员方法声明为静态的(static)。
静态变量的特点:静态变量默认值和实例变量一样;静态变量的值是所有对象共用,属于类的,所以又叫做类变量;允许访问时,可以通过类名.变量名来进行访问,当然也可以使用对象名.变量名来进行访问(不推荐);不同于实例变量,任何一个对象修改静态变量,都会导致整个使用该变量的对象所使用的该变量值改变。
静态方法的特点:静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(不推荐);静态方法可以被子类继承,但不能被子类重写;
静态的注意事项:非静态可以直接访问静态,也可以访问非静态的,但是非静态只能访问非静态的。静态的方法和静态的代码块中,不允许出现this和super关键字,如果有重名问题,使用“类名.”进行区别。
代码示例:
public class Student {
public String name;
public int age;
//static可以修饰属性,也可以修饰方法
//静态属性叫类变量,静态属性全类用一个,任何一个对象对静态属性修改,都会影响到全部
public static String school;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getInfo() {
return "name:" + name + ",age:" + age;
}
//静态方法也是可以直接用类调用
//静态方法和普通方法唯一的区别是静态方法只 能访问静态成员(属性,方法),普通方法都可以访问
public static void methodOne() {
System.out.println("in methodOne");
System.out.println(school);
// System.out.println(name);
}
}
public class TestStudent {
public static void main(String[] args) {
//static修饰的属性或者方法不需要对象,可以直接用类调用
//静态属性随着类的加载已经在方法区分配内存
Student.school = "清华";
Student s1 = new Student();
Student s2 = new Student();
s1.name = "Tom";
s2.name = "Jack";
s1.age = 18;
s2.age = 19;
System.out.println(s1.getInfo());
System.out.println(s2.getInfo());
}
}
1.8.2:封装与私有关键字(private)
封装:随着我们系统越来越复杂,类会越来越多,那么类之间的访问边界必须把握好,面向对象的开发原则要遵循“高内聚、低耦合”,而“高内聚,低耦合”的体现之一:
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用
隐藏对象内部的复杂性,只对外公开简单和可控的访问方式,从而提高系统的可扩展性、可维护性。通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
实现封装就是指控制类或成员的可见性范围?这就需要依赖访问控制修饰符,也称为权限修饰符来控制。
外部类:public和缺省
成员变量、成员方法、构造器、成员内部类:public,protected,缺省,private
成员变量私有化后,其他类若想访问,有没有一种方法来进行访问了。答案是有,java提供了get/set方法来对私有变量进行操作。
示例代码:
public class Student {
//私有属性本类使用
private String stuName;
private int stuAge;
/* public Student() {
}
public Student(String stuName, int stuAge) {
this.stuName = stuName;
this.stuAge = stuAge;
}*/
//使用set方法为私有属性赋值
public void setStuName(String stuName) {
this.stuName = stuName;
}
//使用get方法获取私有属性的值
public String getStuName() {
return stuName;
}
//使用私有属性并使用set方法的好处是:它可以对属性值进行设置,避免不正确的属性值
public void setStuAge(int stuAge) {
if (stuAge < 0) {
this.stuAge = 0;
} else {
this.stuAge = stuAge;
}
}
public int getStuAge() {
return stuAge;
}
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student();
s1.setStuName("Tom");
s1.setStuAge(18);
System.out.println(s1.getStuName()+s1.getStuAge());
}
}
1.8.3:继承
概念:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成某种关系。 其中,多个类可以称为子类,也叫派生类;多个类抽取出来的这个类称为父类、超类(superclass)或者基类。继承可以提高代码的扩展性和复用性。
使用extends关键字就可以实现一个子类继承另外一个父类。
示例代码:
public class Pet {
private String name;
private int age;
private String type;
public Pet() {
}
public Pet(String name, int age, String type) {
this.name = name;
this.age = age;
this.type = type;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public String getInfo() {
return "名字:" + name + ",年龄:" + age + ",品种:" + type;
}
public void play(){
System.out.println("和主任玩耍");
}
}
//Dog extends Pet Dog类继承Pet类,Dog是子类,Pet是父类。
//子类可以继承父类所有的属性和方法,但是构造器不能继承
//java只支持单继承,不支持多重继承,即不能同时继承两个类
//java支持多层继承,即一个类可以继承一个子类
//一个父类可以同时拥有多个子类
//若一个类没有显示的父类,则它继承于Object类,即Object类是所有java类的总父类
public class Dog extends Pet {
//可以在父类的基础上增加属性和方法
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void work(){
System.out.println("工作");
}
}
public class TestOne {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("旺财");
System.out.println("名字" + dog.getName());
dog.play();
dog.work();
Cat cat = new Cat();
cat.setName("汤姆");
System.out.println("名字" + cat.getName());
cat.play();
}
}
子类虽不能继承父类的构造器, 但是子类可以调用父类的构造器
示例代码:
public class Pet {
private String name;
private int age;
public Pet() {
System.out.println("父类无参");
}
public Pet(String name, int age) {
System.out.println("父类有参");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Dog extends Pet{
private String type;
public Dog() {
System.out.println("子类无参");
}
// public Dog(String name, int age) {
// super(name, age);
// System.out.println("子类有参");
// }
public Dog(String name, int age) {
super(name, age);
System.out.println("子类有参");
}
public Dog(String name, int age, String type) {
super(name, age);
this.type = type;
System.out.println("子类增加有参");
}
public class TestDog {
public static void main(String[] args) {
Pet pet1 = new Pet();
System.out.println("父类无参构造结束---------");
Pet pet = new Pet("小宝",12);
System.out.println(pet.getName()+pet.getAge());
System.out.println("父类有参创建结束-----------------------");
Dog dog = new Dog();
System.out.println("子类无参构造结束---------");
Dog dog2 = new Dog("张飞",12);
System.out.println(dog2.getName()+dog2.getAge());
System.out.println("子类有参构造结束");
Dog dog3 = new Dog("zhao",12,"bai");
System.out.println(dog3.getName()+dog3.getAge()+dog3.getType());
}
}
总结:一个类没有显式构造器时,java自动提供一个隐式无参的构造器。 子类继承父类时,子类如果没有显式的构造器,也会同样创建一个隐式无参的构造器。 子类这个隐式无参的构造器,会先调用父类隐式无参的构造器。 如果子类有一个显式有参的构造器,这个构造器的第一句代码必须为super(父类属性名1,父类属性名2), 子类若有父类没有的属性,后面则可使用 this.属性名 = 属性名 来初始化这个属性。
当子类从父类继承的方法无法体现子类的特征时,子类能否对这个方法进行修改以反应子类的特征?答案是可以,java提供了方法的重写。
1.8.4:方法的重写
子类认为从父类继承的方法无法体现子类的特征,方法重写 方法重写:必须发生在子类中,子类编写一个和父类方法方法名,参数列表一样的方法 一旦发生方法重写,子类对象再调用的是方法一定是子类重写后的方法 在子类类体里可以使用super关键字来调用父类重写前的方法。 父类方法的返回类型如果是基础数据类型和void时,子类返回类型一致;父类如果是引用数据类型,子类返回类型必须小于等于父类类型 父类如果抛出异常,子类必须抛出同样的异常或者抛出父类异常的子异常
示例代码:在上面代码Dog子类中重写父类Pet 中的play方法
@Override
//override检查是否为方法重写,可写可不写,建议写,方便阅读代码
public void play(){
super.play();
System.out.println("玩飞盘");
}
}
重写和重载是一样的吗?
并不是,首先重载后的方法和重载前的方法并不是同一个方法,但重写后的方法是同一个方法。重载发生在同一个类中,方法名一样,参数列表不一样,但是对返回类型无要求;重写发生在子类中,方法名和参数列表必须一样。