day07
1. 构造方法
1.1 构造方法的定义和使用
- 构造方法 : 构造器, 构造函数, 使用英文单词Constructor 表示
- Person p = new Person();
对象创建的过程中, ()表示构造方法的调用
构造方法主要功能就是为了给对象的成员变量进行赋值, 当创建对象时, JVM虚拟机主动调用构造方法, 当构造执行完, 对象也创建完毕, 对象中成员变量有值
- 构造方法的语法结构:
修饰符 构造方法名(参数列表){
// 给成员变量进行赋值;
}
- 说明:
1) 修饰符 : 通常使用public公共修饰
2) 构造方法没有返回值类型, 连void都不写
3) 构造方法名 : 必须和类名一致
4) 因为构造方法没有返回值类型, 所以不需要写return ,如果一定要写return;
- 构造方法运行机制:
1) 每次创建对象, JVM虚拟机主动调用指定构造方法一次
2) 构造方法无法通过对象名.主动调用
代码
package com.ujiuye.constructor; public class ConstructorClass { private String name; private int age;
// 定义出构造方法 /* 修饰符 构造方法名(参数列表){ // 给成员变量进行赋值; }*/ public ConstructorClass(String name, int age) { this.name = name; this.age = age; }
/* public ConstructorClass() { System.out.println("我是构造,执行了"); }*/
// alt + shift + s : 快捷键, 可以到里面选择需要生成的代码, 包括set和get public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
package com.ujiuye.constructor; public class TestCon { public static void main(String[] args) { // ConstructorClass(): 表示调用ConstructorClass()空参数构造 // ConstructorClass cc = new ConstructorClass(); // 构造方法调用需要传递实际参数 ConstructorClass cc1 = new ConstructorClass("张三",20); System.out.println(cc1.getName()); System.out.println(cc1.getAge()); // 构造方法不能主动调用, 只能依靠每次创建对象JVM虚拟机主动调一次 // cc1.ConstructorClass("张三",20); } } |
1.2 构造方法使用的注意事项
1. 构造方法参数列表:
a : 定义一个构造,构造方法可以有参数列表, 创建对象时, 调用有参构造, 需要传递实际参数, 可以通过参数列表给对象中的成员变量进行赋值
b : 定义一个构造, 构造方法可以没有参数列表, 创建对象时,构造小括号就为空, 只能进行默认赋值
- 如果一个类型没有手动定义任何构造, 系统会自动为类型创建出一个空参数构造方法
- 如果手动在类型中定义出了构造, 不管手动定义的构造是空参数还是有参数, 系统都不会再自动创建出任何构造
- 构造方法也可以进行方法重载:
定义在同一个类中, 方法名相同, 参数列表不同, 与方法的返回值类型无关
注意 : 如果类型中定义有参数构造, 请你将空参数构造添加上
代码
package com.ujiuye.constructor; public class ConClass { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 空参数构造 public ConClass() { name = "张三"; age = 35; } // 有参数构造 public ConClass(String name,int age) { this.name = name; this.age = age; } } |
package com.ujiuye.constructor; public class TestConClass { public static void main(String[] args) { // 空参数构造调用 ConClass con = new ConClass(); System.out.println(con.getAge());// 35 System.out.println(con.getName());// 张三 // 有参数构造调用 ConClass con1 = new ConClass("小花", 18); System.out.println(con1.getAge());// 18 System.out.println(con1.getName());// 小花 } } |
1.3 this关键字在构造中的使用
1. this关键字 : 第二种使用方式, 在同类的构造之间进行构造方法的调用
this(被调用构造的实际参数列表);
- this() : 构造之间的调用, 语句必须放置在构造方法的有效行第一行
代码
package com.ujiuye.constructor; public class ConThis { private String name; private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public ConThis() { System.out.println("我是空can构造"); }
public ConThis(String name) { // 空参数构造调用 this(); this.name = name; System.out.println("我是name赋值构造"); }
public ConThis(String name,int age) { // 构造调用,传递实际参数 // this(); // Constructor call must be the first statement in a constructor this(name); this.age = age; System.out.println("我是所有变量赋值构造"); } } |
package com.ujiuye.constructor; public class TestConThis { public static void main(String[] args) { ConThis ct = new ConThis("小花", 15); System.out.println(ct.getAge()); System.out.println(ct.getName()); } } |
1.4 创建对象同时成员变量赋值过程
Person p = new Person();
创建对象过程中, 成员变量有可能会经历3种赋值过程
- 对象在堆内存中开辟空间时, JVM虚拟机默认赋初值过程
- 显示赋值 : 定义成员变量同时, 就直接给成员进行赋值
- 构造方法赋值
3种赋值顺序:
JVM虚拟机赋值----->显示赋值覆盖掉JVM默认值---->构造方法将显示赋值覆盖掉
注意 : 所有给对象成员变量赋值过程中, 谁也无法取代set方法功能给成员赋值的存在意义
代码
package com.ujiuye.constructor; public class Person { // 姓名: 默认赋值 private String name; // 年龄 : 显示赋值 private int age = 20; // 性别: 构造方法赋值 private String sex = "男";
// 通过构造给成员变量sex进行赋值 public Person(String sex) { this.sex = sex; }
public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } |
package com.ujiuye.constructor; public class TestPerson { public static void main(String[] args) { Person p = new Person("nv"); System.out.println(p.getAge());// 20 System.out.println(p.getName());// null System.out.println(p.getSex());// nv
// 通过set方法给sex成员进行赋值 p.setSex("泰国"); System.out.println(p.getSex());// 泰国 } } |
2.static静态
2.1 static概念的引入
1.没有静态:
某一个类型, 所有对象都维护一个相同的成员变量值, 问题: 每一个对象中都维护一遍相同的成员值, 浪费内存; 并且如果相同的成员变量值需要修改, 每一个对象都需要修改一遍, 维护难度极大
2.有静态:
某一个类型, 所有对象都维护一个相同的成员变量值,那么直接将这个成员变量使用static静态修饰, 静态成员属于类, 不属于任何对象, 但是因为静态具有共享性, 于是可以被所有的对象同享使用, 如此解决多次维护成员浪费内存的问题; 因为静态成员只维护在类中(.class字节码文件中), 独一份, 维护时,修改唯一的成员即可, 极大的降低了维护的难度
2.2 静态在内存中的存储过程
静态成员会随着类型的.class字节码文件一起加载进入到静态区域中, 因此静态只属于类, 不在任何对象中存储, 但是可以被所有的对象共享使用
代码
package com.ujiuye.staticdemo; public class Student { String name; String id; static String schoolName = "第一中学"; } |
package com.ujiuye.staticdemo; public class TestStudentStatic { public static void main(String[] args) { Student s = new Student(); System.out.println(s.schoolName);// 第一中学 s.schoolName = "一中"; Student s1 = new Student(); System.out.println(s1.schoolName);// 一中 } } |
2.3 静态的特点
1. 使用static关键字进行修饰,可以修饰方法功能, 也可以修饰成员变量
2. 静态跟着类一起加载到方法区(静态区域)进行存储
3. 静态优先于对象存在于内存中, 但是可以被所有的对象共享使用
4. 静态成员访问方式:
a : 对象名.调用; (不推荐使用)
b : 类名.直接调用; (最推荐的,静态成员应有的调用方式)
注意 : 非静态成员变量, 方法功能, 只能创建对象之后才能使用
2.4 静态使用的注意事项
总结 : 静态方法中,不能直接使用非静态成员变量,方法功能
因为静态属于类, 不需要创建对象可以直接使用, 而非静态必须要创建对象后才能使用, 因此先进入内存中的静态成员无法直接使用后进入到内存中的非静态成员
- 静态方法中不能直接调用非静态方法 , 创建对象之后, 使用对象名.调用方法
- 静态方法中不能直接调用非静态成员变量, 创建对象之后, 使用对象名.调用成员
- 静态方法中, 不能使用this关键字, 因为this表示本类对象引用,先有对象才能使用this关键字, 静态优先于对象存在, 使用静态时, 对象还不存在,因此不能直接使用对象之后的this关键字
代码
package com.ujiuye.staticdemo; public class Demo01_静态不能使用非静态 { int i = 10; public static void main(String[] args) { eat(); // 1. 静态方法中,不能直接使用非静态方法功能 // sleep(); // 非静态创建对象之后,才能使用 Demo01_静态不能使用非静态 demo = new Demo01_静态不能使用非静态(); demo.sleep(); //Cannot make a static reference to the non-static field i //System.out.println(i); // 2. 非静态创建对象之后,才能使用非静态成员变量 System.out.println(demo.i); // 3. Cannot use this in a static context 静态方式中不能直接使用this关键字 //System.out.println(this.i); } public static void eat() { System.out.println("吃饭"); } public void sleep() { System.out.println("睡觉"); } } |
2.5 静态成员变量和非静态成员变量的比较
- 所属不同:
a : 静态成员变量, 属于类
b : 非静态成员变量, 属于对象
- 存储在内存中区域不同:
a : 静态成员变量, 跟着类存储在方法区中静态区域中
b : 非静态成员变量, 跟着对象存储在堆内存中
- 生命周期不同:
a : 静态成员变量, 生命周期与.class字节码文件生命周期一样, 当使用一个类型, .class字节码文件进内存, 静态成员出生, 当整个类都运行完毕, .class字节码才会变成垃圾, 静态成员跟着文件消亡
b : 非静态成员变量, 生命周期与对象生命一致, 当new对象是, 成员变量出生, 当对象再无可用之处, 对象变成垃圾, 成员变量随着对象消亡
- 访问方式不同:
a : 静态成员变量, 访问方式由2种
对象名.调用;
类名.直接调用;
b : 非静态成员变量, 对象名.调用;
2.6 工具类(了解,文档注释掌握)
1. 工具类 : 就是一个普通类, 但是类中封装了很多方法功能, 为了让开发人员可以直接使用, 帮助开发过程中解决常见问题
2. 工具类的举例:
ArraysTool : 数组工具类, 封装对于数组相关操作
1) 封装数组遍历
2) 封装数组中的求最大值
3) 封装数组中的求最小值
4) 封装数组反转功能
5) ...
- 文档注释 : (需要掌握)
也是一种注释形式, 通过注释将类,功能描述非常清楚
/**
@author 作者
@version 版本, 表示代码更迭版本 1.0 1.1 1.2 2.0 2.1 ...
@param 参数, 用于表示方法功能参数列表
@return 返回值, 用于表示方法功能返回值类型
*/
- 当代码设计好之后,交付给客户都是.class字节码文件, 但是客户无法读懂.class字节码, 于是需要给代码生成对应的操作文档, 而代码中的文档注释, 会同步到操作文档中
- 生成操作文档(了解,日后开发不需要开发人员生成操作文档)
JDK的bin文件夹路径下, 有应用程序命令javadoc, 为了生成java代码操作文档
1) 定位到需要生成操作文档的指定文件所在的路径下
2) 使用命令 : javadoc -d api -author -version 需要生成操作文件的.java
3) 查看操作文档:
打开指定的文件夹api, 找到index.html网页文件, 双击打开查看
代码
package com.ujiuye.tool; /** * @author lyl * @version 1.0 */ public class NumberTool { /** * 求两个整数的和 * @param x,第一个整数 * @param y,第二个整数 * @return x+y, 两数和 */ public int getSum(int x, int y) { return x + y; } } |
2.7 Arrays工具类
- Arrays : 工具类, 因为类型中封装了对于数组一些相关操作, 是JDK提供的核心类库中其中一个类型, 来自于java.util包, 使用需要导包
- Arrays工具类, 在API中没有给出构造方法的使用, 证明类型不需要创建对象, 表示出这个类型中而定所有功能全部是静态修饰的, 类名.直接调用
- Arrays工具类中常用方法:
1) sort(int[] arr) : 将参数数组arr中的元素, 进行默认的升序排列(从小到大), 没有返回值类型
2) toString(int[] arr) : 将参数数组中的元素获取到, 拼接成一个字符串进行返回, 返回值类型String类型
3) binarySearch(int[] arr, int key): 查找参数key在数组arr中出现的索引位置
a : 要求参数数组升序排列
b : 如果找到key在arr中的索引值, 那么返回一个 >= 0 数值; 如果key在arr数组中不存在,那么返回负数
代码
package com.ujiuye.tool; import java.util.Arrays; public class ArraysDemo { public static void main(String[] args) { int[] arr = {12,3,67,88,-9}; String s = Arrays.toString(arr); System.out.println(s); // 1. sort(int[] arr) : 将参数数组arr中的元素, 进行默认的升序排列(从小到大), 没有返回值类型 Arrays.sort(arr); // 2. toString(int[] arr) : 将参数数组中的元素获取到, 拼接成一个字符串进行返回, 返回值类型String类型 System.out.println(Arrays.toString(arr)); /* 3.binarySearch(int[] arr, int key): 查找参数key在数组arr中出现的索引位置 a : 要求参数数组升序排列 b : 如果找到key在arr中的索引值, 那么返回一个 >= 0 数值; 如果key在arr数组中不存在,那么返回负数*/ int index = Arrays.binarySearch(arr, 67); System.out.println(index);// 3 int index1 = Arrays.binarySearch(arr, 72); // [-9, 3, 12, 67, 72, 88] System.out.println(index1);// -5 } } |
3.继承
3.1 继承的概述
1. 继承面向对象的一大特征
2. 继承: 描述类与类之间的关系,子父类关系
3. 使用extends : 关键字, 让类与类之间具有子父类关系
class A{}
class B extends A{} // B类继承A类
A类: 作为被继承的类, 称为父类, 超类, 基类
B类 : 用于继承的类, 称为子类, 派生类
3.2 继承发生场景
同一个类别的事物, 将多个事物的共性,向上抽取到一个父类中, 让父类实现共性内容, 让其余事物作为这个父类的子类存在, 子类中只需要实现每一个子类特有的内容即可, 子类也可以通过继承关系, 使用父类中的共性内容
举例 :
猫类 : 吃饭 抓老鼠
狗类 : 吃饭 看家
猫和狗都属于动物(同类别事物), 两种动物都需要吃饭eat(), 抽取出一个父类Animal动物类, 实现共有eat方法, 让猫和狗作为Animal动物的子类, 猫只需要实现抓老鼠功能即可, 狗只需要实现看家功能即可, 两子类从父类Animal中直接继承使用eat功能
注意: 继承都是属于关系, is a
猫属于动物; 狗属于动物;
代码
package com.ujiuye.extendsdemo; public class Animal { public void eat() { System.out.println("吃饭"); } } |
package com.ujiuye.extendsdemo; public class Cat extends Animal{ /*public void eat() { System.out.println("吃饭"); }*/ public void catchMouse() { System.out.println("抓老鼠"); } } |
package com.ujiuye.extendsdemo; public class Dog extends Animal{ /*public void eat() { System.out.println("吃饭"); }*/ public void lookHome() { System.out.println("看家"); } } |
package com.ujiuye.extendsdemo; public class TestAnimal { public static void main(String[] args) { // 子类对象创建 Cat c = new Cat(); c.catchMouse();// Cat类自定义功能 c.eat(); // eat方法功能从父类Animal中继承使用 Dog d = new Dog(); d.lookHome(); // Dog类自定义功能 d.eat();// eat方法功能从父类Animal中继承使用 } } |
3.3 继承的注意事项
1. 父类中的私有成员子类无法继承使用(包括私有成员变量, 私有方法功能)
2. 父类中的构造方法无法被子类继承, 但是子类构造可以调用父类构造
构造方法名与类名一致, 父类构造名是父类名, 子类构造需要子类名, 因此名字冲突, 因此父类构造方法无法被子类继承使用
代码
package com.ujiuye.extendsdemo; public class Fu { int i = 10; private int j = 20; public int getJ() { return j; } public void setJ(int j) { this.j = j; } public void fun() { System.out.println("fun方法功能---父类"); } private int getSum(int x, int y) { return x + y; } } |
package com.ujiuye.extendsdemo; public class Zi extends Fu { // 1. 父类中的私有成员变量和私有方法无法被子类继承使用 // Zi继承到了父类中的成员变量i , 也继承到了方法fun, 和get以及set方法 // 子类自定义方法功能 public void useFuExtends() { System.out.println("-----------"); System.out.println(i); fun(); System.out.println("----------"); } } |
package com.ujiuye.extendsdemo; public class Test继承注意事项 { public static void main(String[] args) { // 1. 创建一个子类对象 Zi z = new Zi(); System.out.println(z.i); // System.out.println(z.j); 父类私有不能被子类继承 z.fun(); // z.getSum(3,5); 父类私有不能被子类继承 z.useFuExtends(); // 子类通过继承到的setJ方法, 可以给父类 的私有成员变量j赋值 z.setJ(999); // 子类通过继承到的getJ方法, 可以获取父类 的私有成员变量j的值 System.out.println(z.getJ()); } } |
3.4继承使用的特点
- 在java中,类与类的继承关系,都是单继承, 但是可以多层继承
- 单继承 : 一个子类只能有一个直接父类
不支持多继承 : java不支持一个子类有多个直接父类
- 多层继承:
class A{}
class B extends A{} // B类是A类的子类
class C extends B{} // C类是B类的子类
多层次继承体现在 : C类可以继承使用B类和A类中所有可继承内容
代码
package com.ujiuye.extendsdemo; public class A { public void fun() { System.out.println("A-----------"); } public void fun1() { System.out.println("A-----------"); } } |
package com.ujiuye.extendsdemo; public class B extends A{ public void fun() { System.out.println("B-----------"); } } |
package com.ujiuye.extendsdemo; /* * 1. 单继承 : 一个子类只能有一个直接父类 * public class C extends A,B{ }*/ // 2. 多层次继承体现在 : C类可以继承使用B类和A类中所有可继承内容 // 如果B类和A类中的成员冲突,以直接父类B类为第一继承 public class C extends B{} |
package com.ujiuye.extendsdemo; public class TestC { public static void main(String[] args) { C c = new C(); c.fun(); c.fun1(); } } |