Java学习的第五天
1.关键字this的使用:this表示每个实例对象指向自己的引用,可以出现在实例化方法和构造方法中,不能出现在由static修饰的类方法中
- 在实例方法和构造方法中使用this
this可以出现在类的构造方法和非static修饰的成员方法(也就是实例方法)中,this代表实例对象自身,可以通过this来访问实例对象的成员变量或者调用成员方法。理解不了,不慌,看代码:
public class TestThis {
public String catColor;
public int catHeight;
//一个方法表示哭
public void cry(){
System.out.println("我是一个"+this.catColor+"猫,我正在哭,你听,喵喵喵");
}
//一个方法表示长大了
public void grow(){
this.catHeight++;
System.out.println("调用这个方法,我就会长高,而且我的升高是"+this.catHeight+"cm");
}
//但是构造方法不能省略public
//第一个构造方法
public TestThis(String color){
this.catColor=color;
this.cry();
}
//第二个构造方法
public TestThis(String color,int height){
this(color);
this.catHeight=height;
}
public static void main(String[] args) {
TestThis cat=new TestThis("黄",12);//此时会调用构造函数,也就是说,这里必须由参数,因为没有声明无参构造函数
cat.grow();
cat.grow();
}
}
结果为:
我是一个黄猫,我正在哭,你听,喵喵喵
调用这个方法,我就会长高,而且我的升高是13cm
调用这个方法,我就会长高,而且我的升高是14cm
分析以下代码:这里this有几个点:1.当new一个对象时,会进行实例化,传入的是两个参数,一个是颜色,一个是身高。那么意味着会通过参数类型进入第二个构造方法。这个时候,就需要知道this调用方法:类中的方法一共有两种:普通方法(实例方法):this.方法名称(参数…),构造方法:this(参数…)。所以,"黄"这个字符串就进入了this(color)方法;这里就是this调用构造方法了,此时,会调用第一个构造方法,输出语句:我是一个黄猫,我正在哭,你听,喵喵喵,然后,将传入的身高值,赋给catHeight。
- 区分成员变量和局部变量
成员变量在整个类中有效,局部变量仅在方法内有效。在方法体中的声明变量以及方法的传入参数均称为局部变量,局部变量只有在方法体内有效。如果实例方法中,或类方法中的局部变量名字和成员变量名字相同,这个成员变量在这个方法内暂时失效。(说个人话,变量名一般不一样不就解决了么,只有面试题会有这些东西)如果确实想引用成员变量,则可以使用this关键字。代码如下:
public class TestThis2 {
int x=188;
int y;
public void f(){
int x=3;
y=x;
System.out.println("此时y的值"+y);
y=this.x;
System.out.println("此时y的值"+y);
}
public static void main(String[] args) {
TestThis2 this2=new TestThis2();
this2.f();
}
}
结果为:
此时y的值3
此时y的值188
分析一下:第一个将x的值赋给y,此时x必然是局部变量,因为优先呀(如果实例方法中,或类方法中的局部变量名字和成员变量名字相同,
这个成员变量在这个方法内暂时失效。),第二个x的值赋给y,此时用到了this关键词,那就是引用成员变量,所以就是188
- 返回实例对象本身的引用
this还可以作为类成员方法的return语句参数,用来返回对象本身的引用。→return this。这个this此时表示的就是对象本身。代码如下:
public class TestThis3 {
int age;
float height;
public TestThis3(){//这里是无参的
age=1;
height=10;
}
//下面这个方法没有使用void是因为有返回值,同时看到返回值的类型是TestThis3
//看到这里不要慌,不需要具体了解TestThis3是什么类型,当我们new一个对象时,那个对象的类型,就是类
public TestThis3 grow(){
height=height+10;
age++;
return this;
}
public static void main(String[] args) {
TestThis3 this3=new TestThis3();//注意上下文,这里也无参,其实这里有些寓意,代表刚刚出生
System.out.println("刚刚出生的this3的升高是"+this3.height+"年龄是"+this3.age);
this3=this3.grow();
System.out.println("刚刚出生的this3的升高是"+this3.height+"年龄是"+this3.age);
}
}
结果为:
刚刚出生的this3的升高是10.0年龄是1
刚刚出生的this3的升高是20.0年龄是2
分析代码return this;代表着什么,记住,此时的this代表的是对象本身,因为声明方法时,就是public TestThis3 grow(),这就意味必须有返回值,就是TestThis3这个位置,只要不是void,就得有返回值,简单说int型也得有,对象本身就是this3,而且必须返回构造方法里面的参数内容的值,有些抽象,多理解。
- 使用this调用类的其他构造方法 this调用方法:类中的方法一共有两种:普通方法(实例方法):this.方法名称(参数…),构造方法:this(参数…)。看上面代码就好了
- 类方法中不能使用this:类方法就不需要对象,笔试题会有。
2.面向对象的特性。总共有4个,面试必备
- 第一个特性———封装:将实体特征的属性隐藏起来,对象与外界仅通过公共方法进行交流,这样 可以提高程序的可靠性,安全性,改善程序的可维护性。数据的隐藏与开放对外的接口可以通过访问权限控制符来实现,权限控制符来设置类,成员变量,成员方法等访问权限。Java提供了public,private,protected,默认等4种访问控制符。这个问题说了很多次了,不要烦,我打字更麻烦,看代码。(这里会涉及到包,之前我们也讲过,会先给大家看截图)
每一个JavaTest都是一个包,包里可以有类名相同的存在
第一个是main方法,用来运行类的(注意包名),当然结果也是在这里输出
package JavaTest3;//这里是包
public class Main {
public static void main(String[] args) {
Student daunSang= new Student(19, "山西太原", "段桑", 1716);
Teacher caoCao = new Teacher(35, "四川成都", "曹操", 20201716, "2020001");
caoCao.question(daunSang);
}
}
结果为:
学生的地址:山西太原 学生的年龄:19 学生的名字:段桑
第二个是学生的
package JavaTest3;
public class Student {
public int studentAge;
protected String studentAddr;
String studentName; //默认权限
private int studentAccount;
public Student(int studentAge,String studentAddr,String studentName,int studentAccount){
//这里说一下,this表示的是对象本身,但是前提是实例化以后,注意
//假设Student duanSang=new Student();此时this就相当于duanSang
this.studentAccount=studentAccount;
this.studentAddr=studentAddr;
this.studentAge=studentAge;
this.studentName=studentName;
}
public Student(){
this.studentAge=18;
}
}
第三个是manger的,继承了学生类,学生类的一个子类
package JavaTest3;
public class Manger extends Student {
//该类继承了student类,用来测试同一包内子类的权限控制
void getStudentInfo(){
System.out.println("名字是:"+studentName);
System.out.println("年龄是:"+studentAge);
//System.out.println("账户是:"+studentAccount);
// 当使用了IDEA编译工具时,会自动提示,没有studentAccount,也就是说private修饰的不能被相同包的子类访问
System.out.println("地址是:"+studentAddr);
}
}
第四个是teacher对的
package JavaTest3;
public class Teacher {
public int age;
protected String addr;
String name;
private int account;
String teacherID;
public Teacher(int age,String addr,String name,int account,String teacherID){
this.account=account;
this.addr=addr;
this.age=age;
this.name=name;
this.teacherID=teacherID;
}
public void setInfo(String teacherID){
this.teacherID=teacherID;//当传入teacherID时,会赋给对象
}
public void question(Student student){
System.out.println("学生的地址:"+student.studentAddr+"\t学生的年龄:"+student.studentAge+"\t学生的名字:"+student.studentName);
//System.out.println("学生的账户"+student.studentAccount);studentAccount报红,意味着访问不到
}
}
分析一下:首先,除了Main类是用来调用main方法的,剩下三个,Manger,Student,Teacher是属于一个文件的,其中Manger是Student的子类。Student的属性 studentAge 、studentAddr 、 studentName均可以被Manger,Teacher访问和使用,而private修饰的studentAccount不能被Manger,Teacher访问和使用。这里图片很重要,注意看,注意看
属于封装的---------getInfo与 setInfo
答:出于系统设计的安全性考虑,一般将类的成员属性定义为private形式保护起来,而将类的成员方法定义为public形式对外公开,这是类封装特性的一个体现。一般来说,类中应提供相应的get方法(得private成员变量的值)和set方法(修改private成员变量的值),以便其他类的操作该类的private成员变量。代码如下:
public class StudentInfo {
public String name;
public String studentID;
private String address;
public String phone;
protected String major;
private float GPA;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStudentID() {
return studentID;
}
public void setStudentID(String studentID) {
this.studentID = studentID;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public float getGPA() {
return GPA;
}
public void setGPA(float GPA) {
this.GPA = GPA;
}
//有一个一键生成,右击鼠标,找到Generate,里面有getter和setter方法
//同理:构造方法也有
public StudentInfo(String name, String studentID, String address, String phone, String major, float GPA) {
this.name = name;
this.studentID = studentID;
this.address = address;
this.phone = phone;
this.major = major;
this.GPA = GPA;
}
public void getStudentInfo(){
System.out.println("姓名:"+name+"\t学号:"+studentID+"\t住址:"+address+"\t电话:"+phone+"\t专业:"+major+"\t绩点:"+GPA);
}
public static void main(String[] args) {
StudentInfo studentInfo1=new StudentInfo("段桑","20201716","山西太原","182xxxx3691","java",3.0f);
studentInfo1.setGPA(3.9f);
studentInfo1.getStudentInfo();
}
}
结果为:
姓名:段桑 学号:20201716 住址:山西太原 电话:182xxxx3691 专业:java 绩点:3.9
分析代码:set和get方法,按照常理来说,就是修改或获取值
首先在main方法中,new了一个对象,并且,为所有值都附了初始值,此时如果使用get方法,全部都可以获得,在代码中使用了setGPA()方法,修改了绩点,原来初始值是2.0f,修改完以后变为3.9f。
2.第二个特性———继承子类继承父类,父类派生子类,子类还可以在派生子类。(继承就是叫爸爸,派生就是,他是你儿子)继承的关键字使用是extends→格式:class 子类名 extends 父类名【implements<接口名>】(如果说没有使用extends关键字,也就是说此时程序员没有去给他继承一个父类,那么默认他的父类是Java.lang.object类,object类是所有预定义类的父类(Object类是Java中唯一没有父类的类),包含了所有Java的公共属性,常见的有equals(Object obj),hashCode(),toString()等等)
在刚刚的代码中也写了继承的例子,但是这里再来一个:
第一个main方法:
package JavaTest3;
public class Main2 {
public static void main(String[] args) {
Manager manager=new Manager();
manager.setName("段桑");
manager.setDepartment("技术部");
manager.setSalary(15000);
manager.setSpecial("技术部老大");
manager.setSubsidy(1200);
System.out.println("-----------------------------------员工信息--------------------------------------");
System.out.println();//换行
System.out.println(manager.toString());
}
}
结果为:
-----------------------------------员工信息--------------------------------------
Manager{special='技术部老大', subsidy=1200.0, name='段桑', salary=15000.0, department='技术部'}
第二个是Employee类
package JavaTest3;
public class Employee {
protected String name;
protected double salary; //工资
protected String department;//部门
//换记得generate么,右击查找
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
//toString()方法是用来打印(输出)刚刚声明的内容:name ; salary ; department
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", department='" + department + '\'' +
'}';
}
}
第三个是:
package JavaTest3;
public class Manager extends Employee{
//声明时修饰符时private,也就是说这是Manager特有的
private String special;//职位
private double subsidy;//补贴
//老规矩,一键生成
public String getSpecial() {
return special;
}
public void setSpecial(String special) {
this.special = special;
}
public double getSubsidy() {
return subsidy;
}
public void setSubsidy(double subsidy) {
this.subsidy = subsidy;
}
//由于继承,一键生成时,就会多了几个选择,哈哈哈,IDEA好用
@Override
public String toString() {
return "Manager{" +
"special='" + special + '\'' +
", subsidy=" + subsidy +
", name='" + name + '\'' +
", salary=" + salary +
", department='" + department + '\'' +
'}';
}
}
代码分析:在上面的代码中为了实现功能,所以在Employee类中没有定义private的成员变量,通过封装那张图,可以看到,就算是相同包内的子类,也是不能访问父类的private修饰的成员变量。最主要的点在于,main方法中,Manager manager=new Manager();但是,对象manager可以调用Employee类中的方法。
属于继承的------super的使用(笔试,面试都会问的)
- 子类在继承父类时,可能会出现变量隐藏,方法覆盖等现象。**变量隐藏指子类的成员变量与父类成员同名,此时父类的成员变量隐藏。方法覆盖是指子类的方法名与父类的方法名重名,方法的返回值类型,入口参数的数目,类型,顺序都相同,只是方法实现的功能不同,此时父类的方法被覆盖。**如果子类需要调用或访问父类被隐藏的变量或被覆盖的方法,可以使用super关键字实现。(有点类似this在局部变量与成员变量的使用)代码如下:
关键在于第三个:BClass类,请好好看
第一个是main方法
package JavaTest3;
public class Main3 {
public static void main(String[] args) {
AClass aClass=new AClass();
BClass bClass=new BClass();
aClass.p1();
bClass.p1();
}
}
结果为:
这是方法A
a=50
这是方法B
a=10
这是方法A
a=50
super.a=50
第二个是AClass类:
package JavaTest3;
public class AClass {
int a;
float a1;
public AClass(){
a=50;
a1=99.99f;
}
public void p1(){
System.out.println("这是方法A");
System.out.println("a="+a);
}
}
第三个是:BClass类:
package JavaTest3;
public class BClass extends AClass {
int a;//与父类的成员变量名相同,属于变量隐藏现象
public BClass(){
a=10;
a1=123.4f;
}
//与父类的成员方法相同,属于方法覆盖现象
public void p1(){
System.out.println("这是方法B");
System.out.println("a="+a);//此处的a是BClass的变量值
super.p1();//通过super关键字调用被覆盖的父类成员方法
System.out.println("super.a="+super.a);//通过super关键字调用被隐藏的父类成员变量
}
}
- 子类对象的构造:当用子类的构造方法创建一个子类对象时,子类的构造方法总会显式或隐式的先调用父类的某个构造方法。如果子类的构造方法没有明显的指明调用父类的那个构造方法,Java会默认调用父类的无参构造方法;子类也可以根据super显式的调用父类的指定的构造方法,具体是哪一个构造方法要根据super的参数类型决定。代码分析:
第一个是main方法:
package JavaTest3;
public class MainSuper {
public static void main(String[] args) {
SuperClassSon superClassSon1=new SuperClassSon();
SuperClassSon superClassSon2=new SuperClassSon(400);
}
}
结果为:
调用父类的有参构造方法SuperClass(300)
调用子类的无参构造方法
调用父类的无参构造方法
调用子类的有参构造方法SuperClassSon(400)
第二个是SuperClass 父类
package JavaTest3;
public class SuperClass {
private int n;
//父类声明两个构造函数,一个无参,一个有参
public SuperClass(){
System.out.println("调用父类的无参构造方法");
}
public SuperClass(int n){
System.out.println("调用父类的有参构造方法SuperClass("+n+")");
this.n=n;
}
}
第三个是SuperClassSon 子类
package JavaTest3;
public class SuperClassSon extends SuperClass{
private int n;
//子类的构造方法
public SuperClassSon(){
super(300);//通过super显式的调用父类特定的构造方法
System.out.println("调用子类的无参构造方法");
}
public SuperClassSon(int n){
super();//可以通过super调用父类的构造方法,其实是默认
System.out.println("调用子类的有参构造方法SuperClassSon("+n+")");
this.n=n;
}
}
代码分析:当子类创建时,系统会默认自动调用父类的无参构造方法,也就是如果没有用super去特定的指明(根据super()的参数决定),Java默认调用父类的无参构造方法。例如:main方法中SuperClassSon superClassSon2=new SuperClassSon(400);实例化对象,初始化构造方法有参数的,但是,此时的super()中没有任何参数,也就是说调用父类的无参构造方法,所以这个语句有没有,都不影响结果,反正Java会默认调用,是要super()不去特定的指明。
- 对象类型转换:Java中的子类对象可以向上转换为父类对象,例如:SuperClass superClass=new SuperClassSon();父类的方法,变量,子类可以去使用。
3.第三个特性———多态:同一操作作用于不同类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,得到不同的结果。 - 多态性包含编译时的多态性和运行时的多态性两大类,即多态性也分为静态多态性和动态多态性。
- 静态多态性是指定义在一个类或一个函数中的同名函数,根据参数表(类型以及个数)区别语义和执行的功能(说白了,就是重载)。
- 动态多态性是指定义在一个类层次的不同类中的重载函数,他们具有相同的函数原型,需要根据指针指向对的对象所在类来区别语义,他通过动态联编实现。
- **Java从多个方面支持动态性,一方面可以通过方法重载实现多态;另一方面也可以通过继承过程中出现的方法覆盖以及对象类型的转换(父类引用指向子类)实现。**代码如下:
第一个main方法:
package JavaTest4;
public class Main {
public static void main(String[] args) {
Lady missGao=new Lady();
missGao.pet=new Dog();
missGao.petEnjoy();
Lady missDuan=new Lady();
missDuan.pet=new Bird();
missDuan.petEnjoy();
}
}
结果为:
旺旺旺旺........
喳喳喳喳........
第二个为Pet 类:
package JavaTest4;
public class Pet {
int name;
void enjoy(){
System.out.println("宠物高兴");
}
}
第三个为Lady 类:
package JavaTest4;
public class Lady {
Pet pet;
void petEnjoy(){
pet.enjoy();
}
}
第四个为Dog ,Bird 子类:
package JavaTest4;
public class Dog extends Pet{
void enjoy(){
System.out.println("旺旺旺旺........");
}
}
package JavaTest4;
public class Bird extends Pet {
void enjoy(){
System.out.println("喳喳喳喳........");
}
}
代码分析:Lady类的成员变量pet是父类对象。missDuan.pet父类引用指向了子类对象(一个鸟的实例对象),missGao.pet父类引用也同样指向了子类对象(一个狗的实例对象)。此时父类引用指向子类对象,Java只能根据父类引用的具体指向。选择不同类的方法,实现了用相同的接口完成不同的功能。在pet的子类中,和父类有一样的方法,此时进行了重写,覆盖掉原来的语句,实现了多态
4.第四个特性———抽象