今日的任务
面向对象学习的关键
成员变量可以分为2类
静态成员变量(通过static修饰):在class加载阶段就已经被声明,可以通过对象直接使用。
//引用方法
类名.静态成员变量
对象.静态成员变量
实例成员变量,每个对象实例都有自己的数据值。
//引用方法
对象.实例成员变量
public class User {
//成员变量
//静态实例变量,属于类,加载一次,可以被共享访问
public static int onlineNumber = 160;
//实例成员变量,专属于某一个实例对象
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void show(){
System.out.println("onlineNumber为:"+onlineNumber+
" "+this.name+"的年龄为:"+this.age);
}
public static void main(String[] args) {
//类名.静态成员变量
System.out.println(User.onlineNumber);
System.out.println(onlineNumber);
System.out.println(onlineNumber++);
User user1 = new User();
user1.name = "这是怎么回事儿?"; //private修饰的实例对象变量可以在本class中被其他方法调用
user1.age = 20;
user1.show();
user1.onlineNumber++; //极不推荐这样使用
User user2 = new User();
user2.name = "孙悟空";
user2.age = 561;
user2.show();
}
}
内存原理图
注意:在加载class时,就已经为onlineNumber开辟了堆内存空间。
在过去的学习中,有的方法是有static定义的有的没有,两者的区别在于是否可以直接通过对象来调用。
成员方法的分类
练习
public class Employee {
public static String company = "bilibili";
private String name;
private int age;
private String dept;
//用于传输两个员工对象的年龄进入,并返回比较较大的年龄
public static int compareByAge(int a,int b){
return a>b?a:b;
}
//用于输出employee的具体内容
public void showInfos(){
System.out.println("名称:" + this.name +
" 年龄:" + this.age + " 部门:"+ this.dept + " 公司:" + company);
}
public static void main(String[] args) {
System.out.println(Employee.compareByAge(1,10));
System.out.println(compareByAge(2,5));
Employee employee = new Employee();
employee.age =10;
employee.name = "陈睿";
employee.dept = "高层";
employee.showInfos();
}
}
内存存储方法示例
工具类:
工具类中定义的都是一些静态方法,每个方法都是以完成一个共用的功能为目的。
案例:在企业管理系统中,通常需要在一个系统的很多业务处使用验证码进行防刷新等安全控制。
现状分析:如果登录和注册等多处地方都存在验证码逻辑,就会导致同一个功能在多处开发,会出现代码重复度过高。
工具类的好处:调用方便,提高了代码复用
为什么工具类不适用实例方法做?
实例方法需要创建对象调用,此时用对象知识为了调用方法,会浪费内存。
工具类相关注意对象
//实例:在登录与注册过程中需要多次使用验证码的生成功能
public class VerifyTool {
/**
私有构造器
*/
private VerifyTool(){
}
/**
静态方法
*/
public static String createCode(int n){
// 1、使用String开发一个验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// 2、定义一个变量用于存储5位随机的字符作为验证码
String code = "";
// 3、循环
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(chars.length());
// 4、对应索引提取字符
code += chars.charAt(index);
}
return code;
}
}
//登录类
public class Login {
public static void main(String[] args) {
// 验证码:
System.out.println("验证码:" + VerifyTool.createCode(10));
}
}
//注册类
public class Register {
public static void main(String[] args) {
// 验证码:
System.out.println("验证码:" + VerifyTool.createCode(5));
}
}
练习
需求:在实际开发中,经常会遇到一些数组的使用工具类,编写一个ArrayUtils类实现一下功能
- 请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串如[10,20,30,40 ](只考虑一维数组)
- 经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回 平均分。(只考虑浮点型数组,且只考虑一维数组)
- 定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
public class ArrayUtils {
//首先,私有化构造器
private ArrayUtils(){}
//静态声明toString方法
public static String toString(int[] a){
if (a == null) {
return "[]";
}
String rs = "[";
for (int i = 0; i < a.length; i++) {
rs +=a[i]+",";
}
rs+="]";
return rs;
}
//静态声明getAerage方法
public static double getAverage(int[] a){
if (a == null) {
return 0;
}
int sum = 0;
for (double v : a) {
sum+=v;
}
return 1.0*sum/a.length;
}
}
public class Test2 {
public static void main(String[] args) {
int[] arr = {10, 20, 30};
System.out.println(arr);
System.out.println(ArrayUtils.toString(arr));
System.out.println(ArrayUtils.getAverage(arr));
int[] arr1 = null;
System.out.println(ArrayUtils.toString(arr1));
int[] arr2 = {};
System.out.println(ArrayUtils.toString(arr2));
}
}
代码块概述
代码块分类
import java.util.ArrayList;
public class Card {
/**
模拟初始化牌操作
点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
花色: "♠", "♥", "♣", "♦"
1、准备一个容器,存储54张牌对象,这个容器建议使用静态的集合。静态的集合只加载一次。
*/
public static ArrayList<String> cards = new ArrayList<>();
/**
2、在游戏启动之前需要准备好54张牌放进去,使用静态代码块进行初始化
*/
static{
// 3、加载54张牌进去。
// 4、准备4种花色:类型确定,个数确定了
String[] colors = {"♠", "♥", "♣", "♦"};
// 5、定义点数
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
// 6、先遍历点数、再组合花色
for (int i = 0; i < sizes.length; i++) {
// sizes[i]
for (int j = 0; j < colors.length; j++) {
cards.add(sizes[i] + colors[j]);
}
}
// 7、添加大小王
cards.add("小");
cards.add("大");
}
public static void main(String[] args) {
System.out.println(Card.cards);
}
}
什么是设计模式
单例模式
饿汉单例模式
//定义一个单例类
public class SingleInstance {
//定义一个静态变量存储一个对象即可:属于类,与类一起加在一起
public static SingleInstance singleInstance = new SingleInstance();
//单例必须私有构造器
private SingleInstance(){
System.out.println("创建一个对象");
}
public static void main(String[] args) {
}
}
设计步骤:
public class SingleInstanceTest {
//声明一个static实例对象
public static SingleInstanceTest singleInstanceTest;
//私有化构造器
private SingleInstanceTest(){
System.out.println("创建成功!!!");
}
//提供一个方法返回一个单例对象
public static SingleInstanceTest getInstance(){
/*如果还不存在实例化对象,创建一个对象
如果已存在就直接返回已存在的实例
* */
if (singleInstanceTest == null) {
singleInstanceTest = new SingleInstanceTest();
return singleInstanceTest;
}else{
return singleInstanceTest;
}
}
public static void main(String[] args) {
System.out.println(SingleInstanceTest.getInstance());
System.out.println("第二次:");
System.out.println(SingleInstanceTest.getInstance());
}
}
什么是继承?
使用继承的好处
public class People {
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 static void main(String[] args) {
Student student = new Student();
student.setAge(11);
student.setName("李天一");
student.study();
Teacher teacher = new Teacher();
teacher.setAge(30);
teacher.setName("李双江");
teacher.teach();
}
}
//继承People的学生类
class Student extends People{
public void study(){
System.out.println("努力学习");
}
}
//继承People的类
class Teacher extends People{
public void teach(){
System.out.println("教书育人");
}
}
继承设计规范
为什么?
注意:在为子类分配空间的时候,会将数据在一个对象内分两部分存储,分类父类空间和子类空间
子类是否能够继承父类的构造器?
不能,子类有自己的构造器,父类构造器用于初始化父类对象。
子类是否可以继承父类的私有成员?
可以,但是不能直接访问。(即使是父类本身也不能直接调用自己的private成员)
子类是否可以继承父类的静态成员?
Java只支持单继承,不支持多继承。Java支持多层继承。
Object特点:
在子类方法中访问成员变量满足:就近原则
如果子父局部中出现了重名的成员,会优先使用局部,局部没有就使用子类中的,子类有没有才会使用父类中的,如果要优先使用特点变量怎么办?
public class ExtendTest02 {
public static void main(String[] args) {
Sheep sheep = new Sheep();
sheep.show();
}
}
class animal{
public String type = "animal";
public int age = 0;
}
class Sheep extends animal{
public String type = "sheep";
public int age = 0;
public void show(){
String type = "robbot";
int age =10;
System.out.println("父类成员:"+super.type +" "+ super.age);
System.out.println("子类成员:"+this.type +" "+ this.age);
System.out.println("局部成员:"+type +" "+ age);
}
}
什么是方法重写?
方法重写的应用场景
案例演示:
/*
旧手机的功能只能是基本的打电话,发信息
新手机的功能需要能够:基本的打电话下支持视频通话。基本的发信息下支持发送语音和图片。
*/
public class ExtendTest03 {
public static void main(String[] args) {
System.out.println("老手机:");
OldPhone oldPhone = new OldPhone();
oldPhone.call();
oldPhone.sendInfo();
System.out.println("\n新手机");
NewPhone phone = new NewPhone();
phone.call();
phone.sendInfo();
}
}
//老手机类
class OldPhone{
public String number;
public void call(){
System.out.println("打电话!!!");
}
public void sendInfo(){
System.out.println("发信息!!!");
}
}
//新手机类
class NewPhone extends OldPhone{
@Override
public void call() {
super.call();
System.out.println("视频通话!!!");
}
@Override
public void sendInfo() {
super.sendInfo();
System.out.println("发送语音和图片!!!");
}
}
@Override重写注释
方法重写注意事项和要求
子类构造器的特点
super调用父类有参构造器的作用
初始化继承父类的数据。
如果父类中没有无参构造器,只有有参构造器会出现什么现象?
会报错,子类默认执行父类无参构造器。
如何解决?
子类构造器中可以通过书写super(…),手动调用父类有参构造器。
4.8、this和super使用总结。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量,访问本类成员变量 | this.成员方法() | this() |
super | super.成员变量,访问父类成员变量 | super.成员方法() | super() |
class StudentTest {
private String school;
private String name;
public StudentTest(String name){
this.StudentTest(name,"蓝翔");
}
public void StudentTest(String name, String school) {
this.name = name;
this.school = school;
}
}
this(…)和super(…)使用注意点:
class StudentTest {
private String school;
private String name;
public StudentTest(String name){
this.StudentTest(name,"蓝翔");
}
public void StudentTest(String name, String school) {
this.name = name;
this.school = school;
}
}
this(…)和super(…)使用注意点: