高内聚,低耦合
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
属性私有:private
private将属性私有化,让其它程序不能轻易调用该属性
get/set:
提供可以操作private属性的方法
举例1:
在类Student里设置私有属性和调出与赋值这些私有属性的get和set
方法
public class Student { //属性私有(通过private) //名字 private String name; //学号 private int id; //性别 private char sex; //提供一些可以操作这个属性的方法 //提供一些public的get、set方法 //get获得这个数据 public String getName(){ return this.name;//通过getName()获得name属性 } public void setName(String name){ this.name=name;//通过setName()为name属性赋值 } }
在主函数里通过使用类中的set和get方法来实现对私有属性的赋值和调用
public class Application { public static void main(String[] args) { Student s1 = new Student(); s1.setName("史小鹏");//通过Student类里的setName()为name私有属性赋值 System.out.println(s1.getName());//通过Student类里的getName()获得私有的name属性 } } //输出: 史小鹏
举例2:
关于get/set的应用
例如可以检测数据是否合法
Student类
public class Student { //属性私有(通过private) //名字 private String name; //学号 private int id; //性别 private char sex; //年龄 private int age; //提供一些可以操作这个属性的方法 //提供一些public的get、set方法 //get获得这个数据 public String getName(){ return this.name;//通过getName()获得name属性 } public void setName(String name){ this.name=name;//通过setName()为name属性赋值 } public int getId() { return id; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { if(age>=0 && age<=100){ this.age = age; }else{ System.out.println("年龄不合法"); } } }
主函数
public class Application { public static void main(String[] args) { Student s1 = new Student(); s1.setName("史小鹏");//通过Student类里的setName()为name私有属性赋值 System.out.println(s1.getName());//通过Student类里的getName()获得私有的name属性 //输入一个不可能出现的年龄 s1.setAge(999); System.out.println(s1.getAge()); //输入一个正常年龄 s1.setAge(20); System.out.println(s1.getAge()); } } //输出: 史小鹏 年龄不合法 0 20
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
extands:
用来进行扩展,子类是父类的扩展
Java只有单继承,没有多继承
继承是类和类之间的一种关系(类和类之间的关系:继承、依赖、组合、聚合等)
继承关系两个类:一个为子类(派生类),一个为父类(基类)
子类通过extands继承父类
子类可以重写父类的方法(将子类所继承的方法进行修改而不是)
子类可以继承父类的方法(举例1)
一般子类继承的都是public方法,不能继承private(私有)属性和方法(举例2)
在Java中,所有的类都默认继承Object类
打开继承树:Ctrl+H
举例1:
创建父类
//人 类 //父类 //基类 public class Person { public void say(){ System.out.println("说了一句话"); } }
创建子类
//老师类 //子类 //子类继承父类的所有方法 //派生类 //老师继承人(老师is人) public class Teacher extends Person{ }
主函数应用
public class Application { public static void main(String[] args) { //通过子类创建对象 Teacher teacher = new Teacher(); //因为子类继承父类,所以父类的方法子类对象可以直接使用 teacher.say(); } } //输出: 说了一句话
举例2:
父类
//人 类 //父类 //基类 public class Person { private int a=10; int b=10; public void say(){ System.out.println("说了一句话"); } public void say1(){ System.out.println(a); } }
子类
//老师类 //子类 //子类继承父类的所有方法 //派生类 //老师继承人(老师is人) public class Teacher extends Person{ }
主函数
public class Application { public static void main(String[] args) { //通过子类创建对象 Teacher teacher = new Teacher(); //因为子类继承父类,所以父类的方法子类对象可以直接使用 teacher.say(); System.out.println(teacher.b); teacher.say1(); } } //输出: 说了一句话 10 10
super指调用父类
如果子类和父类都定义了相同名字的属性。则在子类中使用属性名或者this.属性名调用的都是子类的属性,而使用super.属性名则调用的是父类属性(举例1)
子类构造器可以调用父类的构造器
子类构造器默认调用了父类的无参构造(举例2)
调用父类的构造器必须放在子类构造器里的第一行(举例2)
调用自身的构造器必须写在第一行(this()调用自身无参构造,this(...)调用自身有参构造)
super()调用父类无参构造,super(...)调用父类有参构造
调用父类的构造器和调用自身的构造器不能同时存在(因为两个都要求写在第一行)
由于父类写了有参构造之后默认的无参构造就没了,又因为子类构造器默认调用无参构造,所以一旦父类写了无参构造就会导致子类无法写构造器。因此,父类如果要写有参构造就一定要加上一个无参构造或者子类调用父类的有参构造(由于父类写了有参构造导致没有了默认的无参构造,所以不写调用父类有参构造的的话会导致子类构造器默认调用父类的无参构造导致出错)(举例3)
举例1:
父类:
//人 类 //父类 //基类 public class Person { String name = "father"; }
子类:
//学生类 //子类 //子类继承父类的所有方法 //派生类 //学生继承人(学生is人) public class Student extends Person{ String name = "son"; public void say(){ System.out.println(name);//输出子类name属性 System.out.println(this.name);//输出子类name属性 System.out.println(super.name);//输出父类name属性 } }
主函数:
public class Application { public static void main(String[] args) { Student student = new Student(); student.say(); } } //输出: son son father
举例2:
父类:
//人 类 //父类 //基类 public class Person { String name = "father"; int age; private int b; //无参构造方法 public Person(){ age=19; b=20; } }
子类:
//学生类 //子类 //子类继承父类的所有方法 //派生类 //学生继承人(学生is人) public class Student extends Person{ String name = "son"; String sex ; public Student(){ //调用父类的构造器,必须写在第一行 super();//默认调用无参构造所以super()可以不用写,如果写的话必须放在第一行 sex = "man"; } public void say(){ System.out.println(sex); System.out.println(age); } }
主函数:
public class Application { public static void main(String[] args) { Student student = new Student(); student.say(); } } //输出: man 19
举例3:
父类:
//人 类 //父类 //基类 public class Person { String name = "father"; int age; //无参构造方法 public Person(int age){ this.age=age; } }
子类1:
//学生类 //子类 //子类继承父类的所有方法 //派生类 //学生继承人(学生is人) public class Student extends Person{ String name = "son"; String sex ; public Student(int age){ //调用父类的有参构造 super(age);//默认调用无参构造,super()可以不用写,如果写的话必须放在第一行 sex = "man"; } public void say(){ System.out.println(sex); System.out.println(age); } }
子类2:
//老师类 //子类 //子类继承父类的所有方法 //派生类 //老师继承人(老师is人) public class Teacher extends Person{ public Teacher(){ //调用父类的有参构造 super(50); } }
主函数:
public class Application { public static void main(String[] args) { Student student = new Student(30); Teacher teacher = new Teacher(); student.say(); System.out.println(teacher.age); } } //输出: man 30 50
重写都是对方法的重写,和属性无关
静态的方法和非静态的方法有区别,区别很大(举例1,举例2)
只有动态方法里的才算重写
重写的快捷键:Alt+Insert :override
举例1(静态方法里):
父类:
//重写都是对方法的重写,和属性无关 public class B { //静态方法 public static void test(){ System.out.println("B=>test()"); } }
子类:
public class A extends B { //A类对父类中的test()方法进行重写 //静态方法 public static void test(){ System.out.println("A=>test()"); } }
主函数:
public class Application { public static void main(String[] args) { //方法的调用只和左边,定义的数据类型有关 A a = new A(); a.test(); //父类的引用指向了子类 B b = new A(); b.test(); } } //输出: A=>test() B=>test()//子类没有重写父类的方法(因为是静态方法)
举例2(动态方法里的重写):
父类:
//重写都是对方法的重写,和属性无关 public class B { public void test(){ System.out.println("B=>test()"); } }
子类:
public class A extends B { //A类对父类中的test()方法进行重写 public void test(){ System.out.println("A=>test()"); } }
主函数:
public class Application { public static void main(String[] args) { //方法的调用只和左边,定义的数据类型有关 A a = new A(); a.test(); //父类的引用指向了子类 B b = new A();//子类重写了父类的方法 b.test(); } } //输出: A=>test() A=>test()//子类重写了父类的方法
需要有继承关系,子类重写父类的方法
方法名必须相同
参数列表列表必须相同
修饰符:范围可以扩大(不能缩小):public>Protected>Default(默认)>private
例如:父类中的方法是Default,则子类可以重写方法为public或Protected(扩大)
抛出的异常:范围,可以被缩小,但不能扩大:ClassNotFoundException-->Exception(大)
多态可以实现动态编译:类型:可扩展性
一个对象的实际类型是确定的,但一个对象的引用类型是不确定的
举例:
//父类Person(),子类Student() Student s1 = new Student();//new Student()是对象的实际类型(确定的) //可以指向的引用类型是不确定的,父类的引用指向子类 Person s2 = new Student();//Person是引用类型 Object s3 = new Student();
父类的引用指向子类时,如果父类方法在子类中被重写,则调用的方法是子类方法;如果不被重写,则调用的方法是父类方法
举例1(被重写):
父类:
//重写都是对方法的重写,和属性无关 public class B { public void test(){ System.out.println("B=>test()"); } }
子类:
public class A extends B { //A类对父类中的test()方法进行重写 public void test(){ System.out.println("A=>test()"); } }
主函数:
public class Application { public static void main(String[] args) { //方法的调用只和左边,定义的数据类型有关 A a = new A(); a.test(); //父类的引用指向了子类 B b = new A();//子类重写了父类的方法 b.test(); } } //输出: A=>test() A=>test()//子类重写了父类的方法
举例2(不被重写):
父类:
//重写都是对方法的重写,和属性无关 public class B { void test(){ System.out.println("B=>test()"); } }
子类:
public class A extends B { }
主函数:
public class Application { public static void main(String[] args) { //方法的调用只和左边,定义的数据类型有关 A a = new A(); a.test(); //父类的引用指向了子类 B b = new A(); b.test(); } } //输出: B=>test() B=>test()
设A是父方法,B是子方法,经过A b = new B();(父类指向引用)之后,调用方法 a.say() :
如果A(父类)没有say()方法而B(子类)有say()方法,则无法调用say()方法;
如果A有say()方法B没有重写say()方法,则调用A的say()方法;
如果A有say()方法但是B重写say()方法,则调用B的say()方法;
设A是父方法,B是子方法,经过B b = new B();(子类指向引用)之后,调用方法 a.say() :
如果A(父类)没有say()方法而B(子类)有say()方法,则调用B的say()方法;
如果A有say()方法B没有重写say()方法,则调用A的say()方法;
如果A有say()方法但是B重写say()方法,则调用B的say()方法;
综上两点:
多态是方法的多态,属性没有多态
父类和子类,有联系,(父子类型转换异常:ClassCastException)
多态存在的条件:
不支持重写的: