学习内容
一、封装
1.基本介绍
封装:是指把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作,才能对数据进行操作
2.实现步骤
- 将属性进行私有化private
- 提供一个公共的set方法,用于对属性判断并赋值
- 提供一个公共的get方法,用户获取属性的值
3.快速入门
要求:定义一个Person类,其中有姓名和年龄的属性,使用封装的思想对属性进行设置与查看,并且年龄在1-120,否则给默认年龄18,名字必须是2-6个字符,否则给默认名字“张三”
package com.test;
public class Test {
public static void main(String[] args) {
//不使用构造方法
// Person person = new Person();
// person.setName("小明");
// person.setAge(130);
// person.p(); //name=小明 age=18
// System.out.println(person.info()); //name=小明 age=18
//使用构造方法
Person penson = new Person("小明", 130);
System.out.println(penson.info()); //name=小明 age=18
}
}
class Person {
String name;
int age;
//无参构造,如果不写也是存在的,最好写一下
public Person(){
}
//构造方法
public Person(String name, int age) {
setName(name);
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
System.out.println("你设置的姓名超出范围,默认设置为张三");
this.name = "张三";
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 1 && age <= 120) {
this.age = age;
} else {
System.out.println("你设置的年龄超出范围,默认设置为18");
this.age = 18;
}
}
//输出信息
public void p() {
System.out.println("name=" + name + " " + "age=" + age);
}
//使用get方法获取信息,并放在string中
public String info(){
return "name="+getName()+" "+"age="+getAge();
}
}
二、继承
1.基本介绍
继承:可以提高代码的复用性、扩展性和维护性,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。
语法格式:
class 子类 extends 父类{
}
- 子类就会有父类中的属性和方法
- 父类又叫 超类或基类
- 子类又叫 派生类
2.快速入门
public class Test {
public static void main(String[] args) {
//子类man的对象
Person man = new man();
man.name= "小明";
man.age = 20;
man.setSex('男'); //可以调用父类中的方法
man.p();
//子类woman的对象
Person woman = new man();
woman.name= "小明";
woman.age = 20;
woman.setSex('女'); //可以调用父类中的方法
woman.p();
}
}
//父类
class Person {
//共同属性
String name;
int age;
char sex;
//共同方法
public void setSex(char sex) {
this.sex = sex;
}
//输出信息
public void p() {
System.out.println("name=" + name + " " + "age=" + age+" "+"sex="+sex);
}
}
//子类
class man extends Person{
public void test(){
//这里的name就是继承它的父类Person中的name
System.out.println("man的姓名:"+name);
}
}
//子类
class woman extends Person{
public void test(){
//这里的name就是继承它的父类Person中的name
System.out.println("woman的姓名:"+name);
}
}
3.注意事项和使用细节
- 子类继承父类所有的属性和方法,非私有的属性和方法可以直接访问, 但是私有属性和方法不能直接访 问,要通过父类提供公共的方法去访问
//父类
class Person {
//共同属性
public String name = "张三";
private int age = 18;
//获取私有属性
public int get(){
return age;
}
}
//子类
class man extends Person{
public void test(){
System.out.println("姓名:"+name);
//因为父类中的age是私有的所以访问不了
//System.out.println("年龄:"+age);
//如果想访问父类中私有的属性,则可以利用父类的公共方法
System.out.println("年龄:"+get());
}
}
- 子类创建对象时必须调用父类的构造器,完成父类的初始化(因为子类构造方法的第一行中有一个隐藏的super())
public class Test {
public static void main(String[] args) {
//子类man的对象
man man = new man(); //父类的无参构造被调用! 子类的无参构造被调用!
}
}
//父类
class Person {
//Person无参构造方法
public Person(){
System.out.println("父类的无参构造被调用!");
}
}
//子类
class man extends Person{
//man无参构造方法
public man(){
System.out.println("子类的无参构造被调用!");
}
}
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不通过
public class Test {
public static void main(String[] args) {
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
man man = new man(); //输出:父类的无参构造被调用! 子类的无参构造被调用!
man man1 = new man(2); //输出:父类的无参构造被调用! 子类的有参构造被调用!
}
}
//父类
class Person {
//Person无参构造方法
public Person(){
System.out.println("父类的无参构造被调用!");
}
}
//子类
class man extends Person{
//man无参构造方法
public man(){
System.out.println("子类的无参构造被调用!");
}
//man有参构造
public man(int x){
System.out.println("子类的有参构造被调用!");
}
}
public class Test {
public static void main(String[] args) {
//如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作
man man = new man(); //输出:父类的有参构造被调用! 子类的无参构造被调用!
}
}
//父类
class Person {
String name;
int age;
//Person的有参构造方法,无参的构造方法则会默认被覆盖
public Person(String name,int age){
System.out.println("父类的有参构造被调用!");
}
}
//子类
class man extends Person{
//man无参构造方法
public man(){
//因为找不到默认的构造器,则会报错,则需要使用super()指定父类中的构造器
super("张三",18);
System.out.println("子类的无参构造被调用!");
}
}
- 如果希望指定去调用父类的某个构造器,则需要显式的调用 : super(参数列表)
public class Test {
public static void main(String[] args) {
man man = new man(); //输出:父类的有参构造被调用! 子类的无参构造被调用!
}
}
//父类
class Person {
String name;
int age;
//无参构造方法
public Person(){
System.out.println("父类的无参构造被调用!");
}
//有参构造方法
public Person(String name,int age){
System.out.println("父类的有参构造被调用!");
}
}
//子类
class man extends Person{
//子类无参构造方法
public man(){
//super()调用父类的无参构造,或者不写默认调用父类的无参构造
//super();
//调用父类的有参构造,注意只能有一个super
super("张三",18);
System.out.println("子类的无参构造被调用!");
}
}
- super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
- super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
- java中所有类都是 Object 类的子类, Object 是所有类的基类(父类)
- 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
- 子类最多只能直接继承一个父类,但可以间接继承多个类 如:A即想继承B又想继承C,可以让B继承C然后A再继承B
- 不能滥用继承,子类和父类之间必须满足一定的的逻辑关系,如 动物和狗
- super在构造器中是默认存在,虽然看不见,但是确实存在
public class Test {
public static void main(String[] args) {
C c = new C();
/*
我是A类
123我是父类有参构造
hello我是子类的有参构造
我是子类的无参构造
*/
}
}
//爷爷类
class A{
public A(){
System.out.println("我是爷爷类");
}
}
//父类
class B extends A{
public B(){
System.out.println("我是父类无参构造");
}
public B(String name){
//默认有个super
System.out.println(name+"我是父类有参构造");
}
}
//子类
class C extends B{
//子类无参构造方法
public C(){
this("hello");
System.out.println("我是子类的无参构造");
}
public C(String name){
super("123");
System.out.println(name+"我是子类的有参构造");
}
}
三、super的使用
1.基本介绍
super代表父类的引用,用于访问父类的属性,方法,构造器
2.基本语法
1.访问父类的属性,但不能访问private私有属性
super.属性名;
2.访问父类的方法,但不能访问private私有方法
super.方法;
3.访问父类的构造器(只能放在构造器的第一句)
super.(参数);
3.使用细节
1.当子类中有和父类中的属性和方法重名时,为访问父类的成员,必须通过super。如果没有重名,则可以使用super、this直接访问,效果是一样的
public class Test {
public static void main(String[] args) {
C c = new C();
c.sum(); //sum方法
}
}
class B{
public void sum(){
System.out.println("sum方法");
}
}
//子类
class C extends B{
public void p(){
System.out.println("p方法");
}
public void cal(){
/*
1.首先找本类中有没有sum方法,如果有,则调用
2.如果没有,则去父类找,如果有,则调用,没有继续往上找,直到Object,如果object也没有就会报错
注意:如果找到sum方法,则需要注意访问修饰符,如果不能访问也会报错
3.sum()和this.sum()两者等价
4.super.sum()表示跳过本类,直接去父类中找sum(),后面逻辑和上面一样
*/
//sum();
super.sum();
}
}
2.如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个父类中都有同名的成员,使用super访问遵循就近原则(注意:其中也跟访问修饰符有关)
public class Test {
public static void main(String[] args) {
C c = new C();
c.sum(); //就近原则:B类中的sum方法
}
}
class A{
public void sum(){
System.out.println("A类中的sum方法");
}
}
class B extends A{
public void sum(){
System.out.println("B类中的sum方法");
}
}
//子类
class C extends B{
public void p(){
System.out.println("p方法");
}
public void cal(){
//不考虑访问修饰符的话,则就近原则
sum();
}
}
4.this和super的区别
No. | 区别点 | this | super |
---|---|---|---|
1 | 访问属性 | 访问本类中的属性,如果本类没有此属性则从父类中继续查找 | 从父类开始查找属性 |
2 | 调用方法 | 访问本类中的方法,如果本类没有此方法则从父类继续查找 | 从父类开始查找方法 |
3 | 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
4 | 特殊 | 表示当前对象 | 子类中访问父类对象 |
四、方法的重写
1.基本介绍
就是说子类中的方法和父类(包括父类的父类)中方法的方法名、返回值类型、参数都一样,其中返回值类型可以不一样,那么就是子类中的方法重写了父类中的方法
2.快速入门
class A{
public void p(){
System.out.println("A类中的sum方法");
}
}
class B extends A{
public void p(){
//方法名、返回值类型、参数列表都一样,说明子类重写父类的p方法
System.out.println("B类中的sum方法");
}
}
3.注意事项
1.如果方法重写,子类方法的返回值类型可以和父类不一样,但要求子类方法的返回值类型必须是父类方法返回值类型的子类 如:父类方法的返回值类型是object 而子类是string,这种情况是可以的,也是重写
//案例一
class A{
public Object p(){
return 1;
}
}
class B extends A{
public String p(){
//方法名、参数列表都一样,返回值类型不一样,也可以说明子类重写父类的p方法
return "bbb";
}
}
//案例二
class A{
public C p(){
return null;
}
}
class B extends A{
//p方法的重写,因为D是C的子类也是可以的,这里的返回值类型是引用类型
public D p(){
return null;
}
}
class C{ }
class D extends C{ }
2.子类方法不能缩小父类方法的访问权限(访问修饰符),反之可以
class A{
public void p(){
}
}
class B extends A{
//子类的访问修饰符不能缩小了父类访问修饰符的范围,所以会报错,反之是可以的
protected void p(){ //错误
}
}
class A{
protected void p(){
}
}
class B extends A{
//子类可以扩大父类重写方法的范围
public void p(){ //正确
}
}
五、方法重写和重载的区别
名称 | 范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载 | 本类 | 必须一样 | 类型、个数、顺序、至少有一个不同 | 无要求 | 无要求 |
重写 | 父子类 | 必须一样 | 相同 | 子类方法返回值类型和父类一样,或者是其子类 | 子类方法不能缩小父类方法的访问范围 |