this关键字
this:传递对象值
this表示当前对象的意思,指向当前被调用的对象,即谁调用,this就指向代表谁
当前哪个对象被创建,this就代表当前对象
this可以用来调用属性、调用方法、调用构造方法
比如Student stu1=new Student();
调用对应的构造方法时,this.name =name;
里面的this就代表的是对象stu1,把用户输入的name值传递并赋值给stu1的属性name
this调用属性
this调用属性的时候,指向的是当前对象
public class Person {
String name;
//和谁聊天的方法
//this表示当前对象的意思,指向方法的当前调用对象
//谁调用,就指向谁
//this在方法中使用的时候,如果方法中存在和属性同名的局部变量
//加上this可以表示指向对象的属性
public void say(String name){
System.out.println(this.name + "和" + name +"正在聊天!");
}
public Person() {
}
//构造方法中的this,在调用属性的时候
//表示,将来通过这个构造方法创建的对象的属性的值就是传入的值
//this就是指向创建的对象
public Person(String name) {
this.name = name;
}
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "张三";
p1.say("王五"); //张三和王五在聊天
Person p2 = new Person();
p2.name = "李四";
p2.say("王五"); //李四和王五在聊天
Person p3 = new Person("张无忌");
Person p4 = new Person("赵敏");
}
}
this在使用的时候,如果方法中存在和属性同名的局部变量,加上this可以表示指向对象的属性。
this调用成员方法
public class Student {
public void say(){
System.out.println("学生在说话!");
}
public void say(String name){
System.out.println("学生在和" + name + "说话");
}
public void sleep(){
say();
//this调用当前类的成员方法的时候,可以省略不写
// this.say();
this.say("张三");
// System.out.println("学生在说话!");
System.out.println("学生在睡觉!");
}
public static void main(String[] args) {
Student s = new Student();
s.sleep();
}
}
this在普通方法中也可以使用,同样表示指向当前对象。
可以通过this关键字调用当前类的成员方法(方法里调用另一个方法)
this调用构造方法
当对象被创建时,就会触发构造方法(不论对象是否被赋值)
this调用构造方法,this只能写在构造方法的第一行
this调用构造方法时:不可以出现相互调用(或者形成死循环),同时一个构造方法里不能有多个this,只能有一个this,并且this在第一行
关于this到底在调用哪个构造方法(看参数列表)
构造方法可以调用普通方法,
普通方法中,不能通过this关键字调用构造方法
但是普通方法本身是可以调用构造方法的(即在普通方法中可以创建一个对象)
public class Demo01 {
String name;
int age;
public Demo01(){
this("jack"); //调用的是name参数的构造方法
System.out.println("这是无参构造!1");
}
public Demo01(String name) {
this(20); //这个调用的是age参数的构造
System.out.println("这是参数为name的构造方法!2");
}
public Demo01(int age) {
this.show();//调用的 普通方法show
System.out.println("这是参数为age的构造方法!3");
}
public void show(){
//普通方法中,不能通过this调用构造方法
//this("jack");
//普通方法中,创建通过new关键字创建对象是允许的
Student s = new Student();
System.out.println("这是普通方法!4");
}
public static void main(String[] args) {
new Demo01(); //
}
}
封装的定义,封装的使用,封装的目的
封装的定义:
封装其实是对象的一种隐藏技术
目的:将对象的属性和方法隐藏起来,同时隐藏一些不想暴露的属性和一些方法的使用细节
用户或者其他对象就不能看到功能的实现,也不能修改这些被隐藏的功能
将来只能通过指定的接口去调用对象的方法,从而达到通信的目的
封装使用目的:为了将设计者和使用者分开
使用者不需要知道实现的细节,只需要设计者提供的方法来访问对象就可以了
封装的使用:封装通过private 关键字来使用(也叫私有化),将这个方法或者属性私有化
问题: 私有化之后的属性,无法被对象直接调用,怎么完成赋值和 值的获取?
对象属性的赋值 :
1,通过 全参的构造方法 赋值
2,通过在类中设定 set方法,对象调用set方法,来完成对象的赋值
获取对象的属性值:
在别的类中,想要获取属性的值,只能通过get方法来获取
总结 :
属性在私有化之后,一般需要给属性指定getter/setter方法
如果类和类之间需要产生属性的数据交互,那么就可以通过 getter/setter方法
public class School {
//属性
private String schoolName;
private int studentNumber;
private int teacherNumber;
private int classNumber;
//set方法,就是普通方法 ,返回值为空,需要传入参数用来设置属性值
public void setSchoolName(String schoolName){
this.schoolName = schoolName;
}
public void setStudentNumber(int studentNumber){
this.studentNumber = studentNumber;
}
public void setTeacherNumber(int teacherNumber){
this.teacherNumber = teacherNumber;
}
public void setClassNumber(int classNumber){
this.classNumber = classNumber;
}
//声明get方法,方法存在返回值,方法没有参数,方法中有return
public String getSchoolName(){
return schoolName;
}
public int getStudentNumber(){
return studentNumber;
}
public int getTeacherNumber(){
return teacherNumber;
}
public int getClassNumber(){
return classNumber;
}
//构造方法
public School(String schoolName, int studentNumber, int teacherNumber, int classNumber) {
this.schoolName = schoolName;
this.studentNumber = studentNumber;
this.teacherNumber = teacherNumber;
this.classNumber = classNumber;
}
public School() {
}
//定义一个普通方法,将对象的信息展示
public void show(){
System.out.println("学校的名称:" + schoolName +
",学校的学生数量:" + studentNumber +
",学校的老师数量:" + teacherNumber +
",学校的教室数量:" + classNumber);
}
public static void main(String[] args) {
//在同一个类的main方法中,对象是可以正常调用属性的
School school = new School();
school.schoolName = "南京大学";
System.out.println(school.schoolName);
}
}
public class SchoolTest {
public static void main(String[] args) {
School s1 = new School();
//private私有化的属性,在不同类中,属性不能被对象直接调用
//s1.schoolName = "南京邮电大学";
//创建对象,并且给对象赋值的方式:
//1,通过全参的构造方法
School s2 = new School("南京邮电大学",
8000, 1000,
2000);
//赋值之后的对象的私有化的属性,仍然无法直接调用
//System.out.println(s2.schoolName);
//对象的普通方法中,可以接收到对象的赋值
s2.show();
//2,通过setter方法去完成属性的赋值
School s3 = new School();
s3.setSchoolName("南京大学");
s3.setStudentNumber(10000);
s3.setTeacherNumber(2000);
s3.setClassNumber(4000);
s3.show();
//想去获取到某个属性值,不能直接通过点的方式拿到
//也可以通过在类中声明一个普通方法,将属性值返回
//通过设置getter 方法将,属性返回
String schoolName = s3.getSchoolName();
System.out.println(schoolName);
System.out.println(s3.getStudentNumber());
System.out.println(s3.getTeacherNumber());
System.out.println(s3.getClassNumber());
}
}
整理:
//set方法
public void setSchoolName(String schoolName){//需要传入参数,但是不需要返回值
this.schoolName = schoolName;
}
//get方法
public String getSchoolName() {//不需要传入参数,但是需要有对应的返回值
return schoolName;
}
小练习:编写一个私有化的学校类,通过上述的私有化数值赋值方法和获取方法完成对应的操作
(set和全参构造方法来赋值,get方法来获取值)
定义的School类(私有属性)
public class School {
private String schoolName;
private int schoolNumber;
private int teacherNumber;
private String schoolAddress;
public School() {
}
//定义一个普通方法,把对象的信息全部展示
public void show(){
System.out.println("学校名称是"+schoolName+" 学校编号是"+schoolNumber+" 老师编号是"+teacherNumber+" 学校地址是"+schoolAddress);
}
public School(String schoolName, int schoolNumber, int teacherNumber, String schoolAddress) {
this.schoolName = schoolName;
this.schoolNumber = schoolNumber;
this.teacherNumber = teacherNumber;
this.schoolAddress = schoolAddress;
}
public void setSchoolName(String schoolName){//需要传入参数,但是不需要返回值
this.schoolName = schoolName;
}
public void setSchoolNumber(int schoolNumber){
this.schoolNumber=schoolNumber;
}
public void setTeacherNumber(int teacherNumber){
this.teacherNumber = teacherNumber;
}
public void setSchoolAddress(String schoolAddress) {
this.schoolAddress = schoolAddress;
}
public String getSchoolName() {//不需要传入参数,但是需要有对应的返回值
return schoolName;
}
public String getSchoolAddress(){
return schoolAddress;
}
public int getSchoolNumber() {
return schoolNumber;
}
public int getTeacherNumber() {
return teacherNumber;
}
public static void main(String[] args) {
School school = new School();
//在同一个类中,私有化属性可以通过 对象名.属性 的方式来赋值和获取值,但是别的类就不能直接获取了,需要通过set和get方法
school.schoolName="清华大学";
System.out.println(school.schoolName);
}
}
对应的schoolTest测试类
public class SchoolTest {
public static void main(String[] args) {
School s1 = new School();
//在别的类中,之前定义的私有属性不能被创建的对象直接调用赋值了
//私有化对象调用和赋值
//1.通过全参的构造方法去赋值:通过方法里面输出的方式间接调用属性。
School s2 = new School("南京邮电大学", 1001, 2000, "南京");
//私有化的属性不能通过 对象名.属性的方式获取值(不管之前有没有被赋值,都不可以直接调用)
s2.show();
//2.使用get和set方法来进行属性获取和属性的赋值 (在对应的类中) set--设置,赋值 get--获取
//set方法就是一种普通方法,返回值为空,但是需要参数传入设计属性值
School s3 = new School();
s3.setSchoolName("南京大学");
s3.show();//通过set方法也可以完成私有化属性赋值的效果
s3.setSchoolAddress("南京");
//私有化属性在其他类中同样不可以直接通过对象名.属性名来获取数值
//同样的跟赋值一样,也可以通过在类中声明普通方法,调用普通方法来获取属性返回值。
//定义一个get方法,来获取私有化属性的值
//get和set方法的作用就是将来完成各个类之间的信息传递与交互(以后的属性都是私有化的)
System.out.println(s3.getSchoolName());
//总结:属性在私有化之后,1只能通过全参构造方法调用定义的普通方法来赋值
//2.通过在类中设定set方法来实现私有化属性的赋值
//而私有化属性值的获取只能通过get方法来进行获取
}
}
包的引用、常用包
包:成为package,就是用来存放类的文件夹
一般,在创建类的时候,一般在类文件的第一行出现,内容是类存在于项目的src目录下所有的路径(从src开始)
包的取名:一般包以公司倒置的域名作为前缀,再加上项目名,包一般都是用小写名字(没有大写字符)
java.long包下的类可以不用导包
导包一定不能导错包,因为将来会用到很多包,而有很多同名的类方法是在不同的包下的,导错了包会报错。
当导入了两个名字相同但是包不同的对象
其中一个对象会自动把包名当做前缀加在对象前面用以区分
常用包:
java.util
java.sql
java.io
导包:使用 import 关键字
访问控制符
分为两种:
访问控制修饰符
java中访问控制修饰符可以用来保护类,变量,方法(构造方法)被访问的情况
private:私有的 在同一个类中可以被调用,不可以修饰类(类本身定义出来就是给别人用的)
private可以修饰构造方法,但这样以后只有类本身自己可以使用该构造方法
default: 默认的(不需要声明,什么都不写)在类所在的同一个包下可以被调用访问,可以修饰类,变量,方法(包括构造方法)等等
protected:受保护的 在不同包里无法使用,在同一个包下可以被访问和调用,或者其子类都可以被访问,不可以修饰类,可以用来修饰变量,方法
public :公共的 所有位置都可以访问被public修饰的类,变量,方法等
非访问控制修饰符
static, final , abstract , synchronized ,volatile
static修饰符的用法
static修饰成员变量
内存组成(栈,堆,方法区)
1.static修饰的变量是该类的所有对象共享的,可以用来在对象之间共享数据(节省空间)(static修饰的属性值存放在方法区的静态区里,当对象要被打印输出时,系统就会去静态区找现在的值,然后直接输出)
可以修饰成员方法和变量。被修饰的方法成为类方法,修饰的变量成为类变量,直接使用
类.方法名or 类.属性名直接调用
public class Student {
String name;
int age;
static String className; //静态的属性,对象共享
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", className=" + className +
'}';
}
}
public class StudentTest {
public static void main(String[] args) {
System.out.println(Student.className);
//System.out.println(Student.name);
Student s1 = new Student();
s1.name = "张三";
s1.age = 20;
s1.className = "1班";
System.out.println(s1);
Student s2 = new Student();
s2.name = "李四";
s2.age = 22;
System.out.println(s2);
Student s3 = new Student();
s3.name = "王五";
s3.age = 21;
System.out.println(s3);
Student s4 = new Student();
s4.name = "王五";
s4.age = 21;
s4.className = "2班";
System.out.println(s4);
}
}
public class StaticDemo {
static int num;
public static void main(String[] args) {
num++;
StaticDemo s1 = new StaticDemo();
s1.num++;
StaticDemo s2 = new StaticDemo();
s2.num++;
StaticDemo.num++;
System.out.println(num); //4
}
}
static修饰成员方法
static修饰方法,随着类的加载而加载,比如main方法,优先于对象存在,即使没有创建这个类的对象,也可以通过类名调用类中的static方法,被类的所有对象共享
静态方法中,只能访问静态成员变量和 静态方法
public class StaticDemo01 {
//普通变量
int number01 = 100;
//静态变量
static int number02 = 200;
public void say(){
}
public static void show(){
//静态方法中,不能使用非静态的成员变量
//System.out.println(number01);
System.out.println(number02);
//静态方法中,也不能调用非静态的成员方法
//say();
}
//main方法也是静态方法
public static void main(String[] args) {
// say();
// System.out.println(number01);
System.out.println(number02);
show();
}
}
static修饰代码块
代码块分类:
1.局部代码块:定义在方法中,用于限定变量的局部周期
2.构造代码块:声明在类中的成员位置,一般在调用构造方法之前会执行构造代码块(在创建对象之前,或者说是在构造方法执行之前)
3.静态代码块:也是声明在类中的成员位置,多了static修饰符,一般在类加载的时候就会被调用,而且只会执行一次
创建一个对象时,先加载类(静态代码块先执行并且只执行一次)然后执行构造代码块(在构造方法执行之前,即在创建对象之前)。
小案例:查看哪个限制性那个后执行
public class StaticDemo02 {
static {
//静态代码块,只执行一次(类加载的时候就执行)
int a=100;
System.out.println(a);
}
{
//构造代码块
int b=200;
System.out.println(b);
}
public StaticDemo02(){
System.out.println("构造方法");//因为构造方法是在构造代码块后面执行
}
{
int c=300;
System.out.println(c);//构造代码块,在创建对象之前执行(构造方法执行之前)
}
static {
int b= 400;//静态代码块,类加载的时候就执行
System.out.println(b);
}
}
测试类代码如下
public class StaticTest {
public static void main(String[] args) {
{
int e = 500;//依照代码执行顺序,代码在s2对象创建之前,所以先执行
System.out.println(e);
}
StaticDemo02 s2 = new StaticDemo02();
StaticDemo02 s3 = new StaticDemo02();
/* 代码执行结果为如下
500
100
400
200
300
构造方法
200
300
构造方法
* */
}
}
继承的定义、继承的好处、如何继承、继承的特征
定义 :
把多个类中,相同的成员提取出来,定义到一个独立的类中。
然后让当前类和独立类之间产生关系,使当前类具有独立类中的成员内容,这种关系,称为继承
有了继承关系后,当前类称为子类,独立类称为父类
写法:
用extends 关键字来实现继承
class 子类名 extends 父类名{}
继承的好处:
1.提高代码的复用性,也可以提高代码的维护性(代码如果有问题,只需要改一个类就行)
2.继承让类与类之间产生了一个关系,是将来学习多态的前提
继承的缺点:
继承会让类的耦合性增强,父类一但发生改变,就会影响到跟他相关的类
会去打破封装性(父类的属性和方法不能设定为private类型,不可封装,否则子类找不到相关父类属性和方法,无法继承)而子类可以通过supper关键字访问父类的构造方法(得到私有属性)或者子类通过调用从父类继承的getter/setter 方法,来完成子类属性和方法的赋值和调用
如果父类的属性和方法被私有化之后,那么就不能继承了(爸爸的私房钱不能给儿子用)
如果想要使用父类的构造方法,必须现在子类中定义自己的构造
然后再通过特殊的方法来访问直接继承的父类的构造方法(super关键字)
super(name,age,gender)
super(name,age, ..............构造方法里的私有化属性)
构造方法没有办法被继承
super表示父类的意思(super只能使用在直接父类上,多重继承不生效)
父类私有化之后,创建子类对象,怎么使用父类的私有属性?
方法一:子类通过super访问父类的构造方法之后,就可以被哪来实例化对象的时候赋值使用了
方法二:子类调用从父类继承的getter/setter 方法,来完成子类属性和方法的赋值和调用
重点:因此不管有没有继承,只要有setter和getter方法,就可以通过getter/setter(或者继承过来),间接完成私有的属性和方法的赋值和调用
java语言里只允许单继承,只能继承一个类,但是可以多重继承
什么时候可以使用到继承?
当两个类之间满足 xxx is a xxxx 关系是时,可以使用继承
继承之后的成员关系
1.成员变量的关系:
如果子类成员变量名和父类变量名不一样,子类调用的就是子类自身的变量名,如果子类的成员变量名和父类的成员变量名一样,这个时候调用的也是自己自身的成员变量
2.成员方法的关系:
成员方法也是类似,子类的成员方法和父类的成员方法,那子类调用的就是自己的成员方法,如果子类的成员方法和父类的成员方法同名,子类还是优先执行调用自己的成员方法。
总结:子类先找自身,再找父类(先找自己有没有,有就直接运行自己的,如果自己没有,再使用父类的)
不管是不是同名的,子类都先优先找自己的,自己的找不到再继承父类的,因此子类继承父类的属性并赋值时,其实是赋值给自己的,而不影响父类的
3.构造方法的关系
只要有继承关系,子类都会默认的访问父类的无参构造,(子类的无参构造访问父类的无参构造)
如果父类没有无参构造,那么代码会报错
如果报错可以怎么解决?
1、给父类加上无参构造
2、子类使用super去访问(父类没有无参构造,则一定声明了其他有参构造)
这个时候子类就可以通过super访问父类的有参构造,但是这个时候子类就不可以使用无参构造创建对象了,只能跟父类一样使用有参构造,创建对象的时候一定要赋值。
如果父类不提供无参构造,那么子类就必须要使用super关键字,而不能使用无参构造创建对象
基本总结:
1.子类继承父类,被继承的父类也被成为超类(基类),子类可以继承父类的所有属性和方法,私有的可以间接继承,不能直接访问
2.java中一个类只能有一个父类(只能继承一个),但是允许多重继承,从而实现继承多个类的效果
3.如果一个创建了一个类,但是这个类没有继承别的类,该类也是继承Object类的
这也是为什么一个新创建的类一开始就有一些现成方法可以使用(其实是继承了Object类得来的)
Object类是所有类的始祖类
4.子类可以拓展属性、方法
5.继承提升了代码的复用性。
super
定义 :super在调用的时候,指的是当前类对象的父类
因为父类的属性私有化之后,不能直接被子类调用,这时候就可以通过super关键字完成调用
super可以用来调用父类的属性、成员方法、构造方法
super只能出现在子类的普通方法和构造方法中
super在子类中构造方法中,只能出现在第一行代码中
super调用父类的属性
super调用父类的属性,不能调用父类的私有属性,所以,将来用super调用父类属性的用法其实很少用,只能调用没有私有化的属性
super调用父类的构造方法
必须要写在子类构造方法的第一行(第一句)super()只能写在第一行
写法:super()
1.关于无参构造的调用,子类的无参构造就会默认访问父类的无参构造(即super括号里不赋值)
如果子类的有参构造,没有显示的访问父类的有参构造,其实也会默认访问父类的无参构造
为什么?
因为子类继承父类,可能会使用父类的数据,所以在子类初始化之前,得先完成父类的数据初始化
2.关于有参构造的调用
super()括号里参数不同,调用父类的构造方法也不同(根据参数列表的属性不同选择调用不同构造方法)
子类可以在构造方法或者普通方法中,通过super调用父类的普通方法
写法:
super.方法名(),这个点方法名的写法可以没有必须写在第一行的限制
public class Person {
String name; //姓名
int age; //年龄
String gender; //性别
//父类的无参构造被注释,子类就无法使用父类的无参构造了
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show(){
System.out.println("我的姓名:" + name
+ ",我的年龄:" + age
+ ",我的性别:" + gender);
}
}
public class Emp extends Person{ //员工类
String deptName; //部门名称,一种扩展
public Emp() {
//子类的无参构造,默认会去访问父类的无参构造
super();
super.show();
}
public Emp(String name, int age, String gender, String deptName) {
super(name,age,gender);
//super(name, age);
this.deptName = deptName;
}
public void show() {
// 通过super调用父类的普通方法
super.show();
System.out.println("我所在的部门:" + deptName);
}
}
public class TestEmp {
public static void main(String[] args) {
Emp emp = new Emp();
emp.deptName = "研发部";
emp.name = "张三";
emp.age = 20;
emp.gender = "男";
emp.show();
Emp emp1 = new Emp("李四", 22, "男", "财务部");
emp1.show();
}
}
创建一个动物类,作为父类 ,有私有化 种类、颜色两个属性,有一个show方法,作为动物的介绍
介绍内容为 : 我的种类是:xx,我的颜色是:xx
声明一个 小狗类,作为子类,有姓名 私有化属性作为扩展 ,子类也有一个show方法,并对父类的show方法做一个扩展,添加一条输出语句: 我的名字是:xx
要求 :通过全参的构造方法,实例化一个狗类对象,并调用show方法
//动物类
public class Animal {
private String type;
private String color;
public Animal(String type, String color) {
this.type = type;
this.color = color;
}
public void show(){
System.out.println(" 我的种类是:" + type+
",我的颜色是:" + color);
}
}
public class Dog extends Animal {
private String name;
public Dog(String type, String color, String name) {
super(type, color); //通过super访问父类的构造方法
this.name = name;
}
public void show(){
super.show(); //调用父类的show方法
System.out.println("我的名字是:" + name);
}
}
public class DogTest {
public static void main(String[] args) {
Dog dog = new Dog("哈士奇", "白色", "二哈");
dog.show();
}
}
重点:
super和this的区别
this指的是当前对象的引用,super指的是父类对象引用
super关键字:
super.父类属性名: 调用父类的属性
super.父类方法名: 调用父类的方法
super() : 调用父类的无参构造函数
super(参数): 调用父类额有参构造函数
this的用法 :
this.属性名 :调用当前对象的属性 (局部变量和成员变量冲突)
this.方法名 : 调用当前对象的方法
this() : 调用当前类的无参构造
this(参数) : 调用当前类的有参构造
如果构造函数的第一行不是this()或者super()。系统默认添加super()
this和super关键字,不能共存
方法重写的定义
概念:
子类继承父类,子类重写父类的方法,方法名相同,参数列表相同,返回值类型相同或者是父类方法返回值的子类,访问修饰符不能严于父类,不能抛出比父类更多的异常
父类的私有方法不能被重写
父类的静态方法,不能被子类重写,
如果子类定义了和父类相同的静态方法或者私有方法,都会被当做子类自己的方法
子类为什么要重写父类方法?
一般是因为父类方法的功能不能满足子类的需求,然后子类对于父类方法做出扩展
即父类定义的方法功能太少了,子类会对其进行重写,对父类方法进行扩充
public class Father {
public void method01(){
System.out.println("这是父类的普通方法");
}
public Father method02(){
return new Father();
}
public void method03(int a,int b){
System.out.println("父类中带参数的方法");
}
public static void method04(){
System.out.println("父类的静态方法");
}
private void method05(){
System.out.println("父类的私有方法");
}
}
public class Son extends Father {
@Override
public void method01() {
System.out.println("这是子类的方法");
}
//子类重写的方法的返回值,可以和父类相同
//或者是父类返回值的子类
@Override
public Son method02() {
return new Son();
}
//@Override //用来标识子类的方法重写了父类方法的
//method03参数和父类的参数不一样,这个方法仍然可以声明
//但是这个时候,它和父类方法没有关系,
// 只是子类自己的一个普通方法
public void method03(int a) {
System.out.println("子类的方法");
}
//@Override
//子类可以声明和父类相同名称的静态方法,
//但是它们之间的关系并不是重写,
//一般子类很少去写和父类同名的静态方法,除非想要将
//父类的静态方法在子类中隐藏
public static void method04(){
System.out.println("子类的静态方法");
}
//@Override
//父类的私有方法不能被子类重写
private void method05(){
System.out.println("子类重写父类的私有方法");
}
}
案例:父类Animal
public class Animal {
private String type;
private String color;
public Animal() {//父类的无参构造一定要写,因为当子类的有参构造里面没有显示super(参数)调用父类的有参构造的话,那么子类的有参构造会默认访问父类的无参构造
}
public Animal(String type, String color) {//父类必须要有全参构造,子类才能通过super(带参数的)访问父类这里的带参构造
this.type = type;
this.color = color;
}
public void show(){
System.out.println("我的种类是:"+this.type+"我的颜色是:"+this.color);
}
public static void method04(){
System.out.println("父类的静态方法");
}
private void method05(){
System.out.println("父类的普通方法,子类要重写成静态方法");
}
}
子类Dog
public class Dog extends Animal{
private String name;
public Dog(){
super();
}
public Dog(String type,String color,String name){
super(type, color); //通过super访问父类的构造方法
this.name=name;
}
// @Override
// public void show() {
// super.show();//可以通过super直接调用父类方法,下面再进行扩展
// System.out.println("我的名称是:"+this.name);
// }
@Override//重写注解(用来标识子类重写了父类的方法,如果注解报错,说明重写失败(不存在重写) )
public void show(){//也可以直接重写父类方法,将其覆盖掉(子类重写方法,参数列表必须一样)
System.out.println("我的名称是:"+this.name);
}
// @Override
// public static void method04(){
// System.out.println("子类的静态方法");//子类无法重写父类的静态方法,而且一般子类不会重写父类的静态方法
// }
// @Override
// private void method05(){//对于父类的私有方法,子类也不能重写
//
// }
//父类的普通方法,子类也不能定义成静态方法并重写(static静态方法是属于类的,会跟随类的加载而加载,而子类重写以后会寻找父类的静态方法,
// 但是父类没有该方法,而且静态方法也不能被重写)
}
方法重写的应用
equals()方法重写
直接使用object 的equals方法(是直接返回地址值),因此自己在实际开发中,需要重写equals方法
public class Student {
private int sid; //学号
private String name; //姓名
private String className; //班级
public Student() {
}
public Student(int sid, String name, String className) {
this.sid = sid;
this.name = name;
this.className = className;
}
@Override
public boolean equals(Object obj) {
//如果比较的两个对象,地址值相同,它们就是同一个对象
if (this == obj){
return true;
}
//如果传入的参数,不是一个Student对象,直接返回false
//通过 instanceof 可以判断某个对象是否是指定类的实例
// 用法 : 对象名 instanceof 类
if (!(obj instanceof Student)){
return false;
}
//判断传入的对象的属性和当前对象的属性的值,是否都是相同的
//传入的参数会被当做是Object类型,将传入的参数,转为Student
Student o = (Student) obj;
if (this.sid == o.sid &&
this.name.equals(o.name) &&
this.className.equals(o.className)){
return true;
}
return false;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", name='" + name + '\'' +
", className='" + className + '\'' +
'}';
}
}
toString()方法重写
当对象在被输出的时候,默认的会访问这个对象类的toString()方法,如果类中没有,就默认访问Object类中的toString()方法。
Object类中的toString()方法如下,表示返回当前类的包名+类名 +@+当前对象hashCode值的16进制
所以输出对象的时候,最后的结果就是一串值
所以将来,类中,一般都会重写toString()方法
相关面试题 :
1,方法重写与方法重载的区别是什么?
方法重写是指继承关系中,子类对于父类同名方法(同样参数列表)的覆盖,本质上是一种继承关系。
而方法重载是指在同一个类中,存在多个同名的方法,方法名相同但是参数列表不同(参数的个数,参数的排列顺序以及参数类型不同),方法的访问修饰符和返回值类型是否相同不作为方法重载的判定点(不影响方法重载)。方法重载包括构造方法重载和普通方法重载。
2,==和equals()方法区别
== 可以用来比较基本类型和引用类型
比较基本类型的时候,比较的是值
比较引用类型的时候,比较的是对象的地址值
equals()方法,是Object类中的方法,一般用来比较对象是否相同
底层代码其实还是 ==,所以如果想要使用equals()方法,一般会重写equals()方法
重写就是将对象的属性挨个比较,看看是否相同,重写之后可以用来比较对象是否相同
String类的equals()方法
重写了Object类中的equals()方法,底层的原理就是将需要比较字符串转为字符数组之后,利用循环,一个个比较数组中的字符值是否相同
3,为什么重写equals()方法,一定要重写hashCode()方法?
因为在Java中,相同的对象,它的hashCode值必须也是相同的
所以在重写equals()方法的同事,要重写hashCode()方法,为了保证他们的hashCode值也相同