目录
一.static关键字
1.static是什么,修饰成员变量的方法
(1)static是静态的意思,可以修饰成员变量和成员方法。
(2)static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问,修改。
成员变量可以分为两类:
(1)静态成员变量(含有static修饰,属于类,内存中只加载一次):常表示在线人数,等需要被共享的信息,可以被共享访问。
package com.day01.demo1_static;
public class User {
/**
* 在线人数
* 注意:static修饰的成员变量:静态成员变量只有一份,可以被共享访问,修改。
*/
public static int onlineNumber = 161;
}
package com.day01.demo1_static;
public class staticFiledDemo1 {
public static void main(String[] args) {
//目标:理解static修饰成员变量的作用和访问特点。
//使用方法:
// 1.类名.静态成员变量 (官方推荐)
System.out.println(User.onlineNumber);
//2.u.onlineNumber (不推荐)
User u = new User();
System.out.println(u.onlineNumber);
}
}
161
161
进程已结束,退出代码为 0
(2)实例成员变量(无static修饰,存在每个对象中):常表示姓名name,年龄age,等属于每个对象的信息。
package com.day01.demo1_static;
public class User {
/**
* 在线人数
* 注意:static修饰的成员变量:静态成员变量只有一份,可以被共享访问,修改。
*/
public static int onlineNumber = 161;
/**
* 实例成员变量,无static修饰,属于每个对象的对象名访问
*/
private String name;
private int age;
public static void main(String[] args) {
//目标:理解static修饰成员变量的作用和访问特点。
//使用方法:
// 1.类名.静态成员变量 (官方推荐)
System.out.println(User.onlineNumber);
//2.u.onlineNumber (不推荐)
User u = new User();
System.out.println(u.onlineNumber);
User u2 = new User();
u2.name = "张三";
u2.age = 21;
System.out.println(u2.name);
System.out.println(u2.age);
//System.out.println(User.name); //报错,原因:私有访问且没有static修饰
//注意:同一个类中静态成员变量的访问可以省略类名
System.out.println(u2.onlineNumber); //不推荐
System.out.println(User.onlineNumber); //推荐
}
}
161
161
张三
21
161
161
进程已结束,退出代码为 0
2.static修饰成员变量的内存原理
注意:同一个类可以直接访问static修饰的成员变量;不同的类必须需要使用 --> 类名.成员变量
3.static修饰成员方法的基本用法
成员方法的分类:
(1)静态成员方法(有static修饰,归属于类),建议用类名访问,也可以用对象访问。
(2)实例成员方法(无static修饰,归属于对象),只能用对象触发访问
package com.day01.demo1_static;
public class Student {
/**
* 实例成员变量:无static修饰,属于对象
*/
private String name;
/**
* 静态成员方法:有static修饰,归属于类,可以被共享访问,用类名或者对象名都可以访问。
*/
public static int getMax(int age1,int age2){
return age1 > age2 ? age1 : age2;
}
/*
实例方法:属于对象的,只能用对象触发访问
*/
public void study(){
System.out.println(name+"好好学习,天天向上");
}
public static void main(String[] args) {
//1.类名.静态成员方法
System.out.println(Student.getMax(10,3));
//注意:同一个类中,访问静态方法,类名可以省略不写。
System.out.println(getMax(10,32));
//study(); //报错了
//2.对象.实例方法
Student s = new Student();
s.name = "猪八戒";
s.study();
//3.对象.静态方法(语法是可行的,但是不推荐)
System.out.println(s.getMax(13,34));
}
}
4.static修饰成员方法的内存原理
5.static的注意事项
static访问注意事项:
1.静态方法只能访问静态的成员,不可以直接访问实例成员。
2.实例方法可以访问静态的成员,也可以访问实例成员。
3.静态方法中是不可以出现this关键字的。
//ps:this代表当前对象的地址
二.static应用知识:工具类
工具类是什么?
类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员共同使用的
案例导学: 在企业的管理系统中,通常需要在一个系统的很多业务处使用验证码进行防刷新等安全控制。
使用工具类的好处 一是调用方便,二是提高了代码复用(一次编写,处处可用)
工具类:开发验证码(static方法篇)
package com.day01.demo2_static_util;
import java.util.Random;
/**
* 工具类
*/
public class wjh_util {
/*
静态方法
*/
public static String createVerifyCode(int n){
//开发一个验证码
//1.定义一个变量记住验证码
String code = "";
//2.定义一个变量记住全部验证码
String date = "abcdefghijklmnopqrstuvwxyz0123456789";
Random r = new Random();
//3.定义一个循环,生成几个随机数,得到几个字符
for (int i = 0; i < n; i++) {
//4.获取随机索引对应的随机索引,链接给code
int index = r.nextInt(date.length());
code = code + date.charAt(index);
}
return code;
}
}
直接调用:
package com.day01.demo2_static_util;
import java.util.Random;
public class Login {
public static void main(String[] args) {
//开发一个验证码
System.out.println("验证码:" + wjh_util.createVerifyCode(6));
}
}
直接调用:
package com.day01.demo2_static_util;
public class Check {
public static void main(String[] args) {
System.out.println("验证码:" + wjh_util.createVerifyCode(5));
}
}
验证码:y28xdg
进程已结束,退出代码为 0
验证码:q4sxj
进程已结束,退出代码为 0
为什么工具类中的方法不用实例方法做?
实例方法需要创建对象调用。
此时用对象只是为了调用方法,这样只会浪费内存。
工具类定义时的其他要求:
由于工具里面都是静态方法,直接用类名即可访问,因此,工具类无需创建对象,建议将工具类的构造器进行私有。
//注意,由于工具类无需创建对象,所以把构造器私有化显得很专业!
private wjh_util(){
}
需求:
在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils :
1.我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10, 20, 50, 34, 100](只考虑整数数组,且只考虑一维数组) :
2.经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组) :
3.定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
三.static应用知识:代码块
代码块概述
1.代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。
2.在Java类下,使用 { } 括起来的代码被称为代码块 。
代码块分为
静态代码块:
1. 格式:static{}
2. 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
3.使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
package com.day03.static_code;
import java.util.ArrayList;
public class StaticDemo1 {
public static String SchoolName;
//public static ArrayList<String> cards = new ArrayList<>(); //有static,只有一份
//目标:先理解代码块有static修饰,属于类,与类一起 <优先> 加载一次,自动触发执行
//可以用于初始化静态资源
static {
System.out.println("===============静态代码块被执行了=============");
SchoolName = "问问";
System.out.println(SchoolName);
// cards.add("3");
//cards.add("4");
}
public static void main(String[] args) {
System.out.println("==============main被执行了=============");
System.out.println(SchoolName);
}
}
===============静态代码块被执行了=============
问问
==============main被执行了=============
问问进程已结束,退出代码为 0
构造代码块(了解,见的少):(实例代码块)
1.格式:{}
2.特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
3.使用场景:初始化实例资源。
package com.day01.demo1_static;
public class StaticDemo2 {
private String name;
public StaticDemo2(){
System.out.println("======无参数构造器被触发执行=======");
}
/**
* 实例代码块:无static修饰,属于对象,每次构建对象时,都会触发一次执行
*/
{
name = "张三";
System.out.println("===========实例代码块被执行了===========");
}
public static void main(String[] args) {
/*
目标:理解实例代码块(构造代码块)
*/
StaticDemo2 s = new StaticDemo2();
System.out.println(s.name);
StaticDemo2 s2 = new StaticDemo2();
System.out.println(s2.name);
}
}
===========实例代码块被执行了===========
======无参数构造器被触发执行=======
张三
===========实例代码块被执行了===========
======无参数构造器被触发执行=======
张三进程已结束,退出代码为 0
四.static应用知识:单例
斗地主案例:
需求: 在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据。
分析: 1.该房间只需要一副牌。
2.定义一个静态的ArrayList集合存储54张牌对象,静态的集合只会加载一份。
3.在启动游戏房间前,应该将54张牌初始化好
4.当系统启动的同时需要准备好54张牌数据,此时可以用静态代码块完成。
package com.day01.demo1_static;
import java.util.ArrayList;
public class StaticTest3 {
/*
1.定义一个静态的集合,这样这个集合只会加载一次,因为当前房间也只需要一副牌
*/
public static ArrayList<String> cards = new ArrayList<>();
/*
2.在程序真正运行main方法前,把54张牌放进去,游戏后续可以直接使用了
*/
static {
//3.正式做牌,放到集合中去
//a.定义一个数组存储全部点数,类型确定了,个数确定了。
String[] size = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//b.定义一个数组存储全部花色,类型确定了,个数确定了。
String[] colors = {"♥","♠","♦","♣"};
//c.遍历点数
for (int i = 0; i < size.length; i++) {
//size[i]
//d.遍历花色
for (int j = 0; j < colors.length; j++) {
//colors[i]
String card = size[i] + colors[j]; //一张牌
cards.add(card);
}
}
//e.单独加入大小王
cards.add("大");
cards.add("小");
}
public static void main(String[] args) {
//目标:模拟游戏启动前,初始化54张牌
System.out.println("新牌:" + cards);
}
}
新牌:[3♥, 3♠, 3♦, 3♣, 4♥, 4♠, 4♦, 4♣, 5♥, 5♠, 5♦, 5♣, 6♥, 6♠, 6♦, 6♣, 7♥, 7♠, 7♦, 7♣, 8♥, 8♠, 8♦, 8♣, 9♥, 9♠, 9♦, 9♣, 10♥, 10♠, 10♦, 10♣, J♥, J♠, J♦, J♣, Q♥, Q♠, Q♦, Q♣, K♥, K♠, K♦, K♣, A♥, A♠, A♦, A♣, 2♥, 2♠, 2♦, 2♣, 大, 小]
进程已结束,退出代码为 0
设计模式,单例模式介绍,饿汉单例介绍模式
什么是设计模式(Design pattern)
1.开发中经常遇到一些问题,一个问题通常有n种解法的,但其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
2.设计模式有20多种,对应20多种软件开发中会遇到的问题。
3. 学设计模式主要是学2点:
(1)这种模式用来解决什么问题。
(2)遇到这种问题了,该模式是怎么写的,他是如何解决这个问题的。
单例模式
1.可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
2.例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间。
单例的实现方式很多
饿汉单例模式。
懒汉单例模式。 … …
饿汉单例设计模式
在用类获取对象的时候,对象已经提前为你创建好了。
设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。
package com.day01.day04_singleinstance;
/*
使用恶汉单例模式实现单例类
*/
public class SingleInstance {
/**
* 2.饿汉单例是在获取对象前,对象已经提前准备好了一个
* 这个对象只能是一个,所以定义静态成员变量记住。
*/
public static SingleInstance instance = new SingleInstance();
/**
* 1.必须把构造器私有化
*/
private SingleInstance(){
}
}
package com.day01.day04_singleinstance;
public class Test1 {
public static void main(String[] args) {
//目标:理解饿汉单例设计的设计步骤
SingleInstance s1 = new SingleInstance();
SingleInstance s2 = new SingleInstance();
System.out.println(s1 == s2);
}
}
懒汉单例设计模式
懒汉单例设计模式
1.在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤:
1.定义一个类,把构造器私有。
2.定义一个静态变量存储一个对象。
3.提供一个返回单例对象的方法
package com.day01.day04_singleinstance;
/**
* 懒汉单例
*/
public class SingleInstance2 {
/*2.定义一个静态变量存储一个对象。
只加载一次,只有一份
注意:最好私有化,这样可以避免给别人挖坑!
*/
public static SingleInstance2 instance;
/**
* 3.提供一个方法,对外返回单例对象的方法
*/
public static SingleInstance2 getInstance(){ //获取一个对象
if(instance == null){
//第一次拿对象,此时需要创建对象
instance = new SingleInstance2();
}
return instance;
}
// 1.定义一个类,把构造器私有。
private SingleInstance2(){
}
}
package com.day01.day04_singleinstance;
public class Test2 {
public static void main(String[] args) {
//目标:理解懒汉单例设计的设计步骤
SingleInstance2 s1 = SingleInstance2.getInstance();
SingleInstance2 s2 = SingleInstance2.getInstance();
System.out.println(s1 == s2);
System.out.println(s2);
}
}
true
com.day01.day04_singleinstance.SingleInstance2@3b07d329进程已结束,退出代码为 0
五.面向对象三大特征之二:继承
1.继承概述、使用继承的好处
什么是继承?
Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。
Student称为子类(派生类),People称为父类(基类 或超类)。
作用:当子类继承父类后,就可以直接使用父类公共的属性和方法了
使用继承的好处:
可以提高代码的复用性
2.继承的设计规范、内存运行原理
继承设计规范:
子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的的属性和行为应该定义在子类自己里面。
为什么?
如果子类的独有属性、行为定义在父类中,会导致其它子类也会得到这些属性和行为,这不符合面向对象逻辑
需求:
1.在传智教育的tlias教学资源管理系统中,存在学生、老师角色会进入系统。
分析:
1.学生信息和行为(名称,年龄,所在班级,查看课表,填写听课反馈)
3.老师信息和行为(名称,年龄,部门名称,查看课表,发布问题)
4.定义角色类作为父类包含属性(名称,年龄),行为(查看课表)
5.定义子类:学生类包含属性(所在班级),行为(填写听课反馈)
6.定义子类:老师类包含属性(部门名称),行为(发布问题)
父类
package com.day01.day06_extends_test;
public class People {
private String name;
private int age;
/**
* 行为:查看课表
*/
public void queryCourse(){
System.out.println(name+"查看课表");
}
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = 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;
}
}
子类
package com.day01.day06_extends_test;
/* 子类
*/
public class Student extends People{
/**
* 子类
* 独有的行为:填写反馈信息
*/
public void writeInfo(){
System.out.println(getName() + "写下了学习语法!");
}
}
测试类
package com.day01.day06_extends_test;
public class Test {
public static void main(String[] args) {
//目标:理解继承地设计思想
Student s = new Student();
s.setName("蜘蛛精"); //使用父类的
s.setAge(999); //使用父类的
System.out.println(s.getName());
System.out.println(s.getAge());
s.queryCourse(); //使用父类的
s.writeInfo(); //使用自己的
}
}
蜘蛛精
999
蜘蛛精查看课表
蜘蛛精写下了学习语法!进程已结束,退出代码为 0
3.继承的特点
继承的特点:
1.子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。
2.Java是单继承模式:一个类只能继承一个直接父类。
3.Java不支持多继承、但是支持多层继承。
4.Java中所有的类都是Object类的子类。
1、子类是否可以继承父类的构造器?
不可以的,子类有自己的构造器,父类构造器用于初始化父类对象。
2、子类是否可以继承父类的私有成员?
可以的,只是不能直接访问。
package com.day01.day7_extends_feature;
public class Test {
public static void main(String[] args) {
//目标:理解继承的特点
// 1、子类是否可以继承父类的构造器?
//不可以的,子类有自己的构造器,父类构造器用于初始化父类对象。
//2、子类是否可以继承父类的私有成员?
Tiger t = new Tiger();
//t.eat(); //报错
//可以的,只是不能直接访问。
}
}
class Animal{
private void eat(){
System.out.println("动物要吃东西");
}
}
class Tiger extends Animal{
}
1、子类是否可以继承父类的静态成员?
有争议的知识点。
子类可以直接使用父类的静态成员(共享)
但个人认为:子类不能继承父类的静态成员。(共享并非继承)
Java只支持单继承,不支持多继承。
package com.day01.day7_extends_feature;
public class Test {
public static void main(String[] args) {
//目标:理解继承的特点
// 1、子类是否可以继承父类的构造器?
//不可以的,子类有自己的构造器,父类构造器用于初始化父类对象。
//2、子类是否可以继承父类的私有成员?
Tiger t = new Tiger();
//t.eat(); //报错
//可以的,只是不能直接访问。
/*
1、子类是否可以继承父类的静态成员?
有争议的知识点。
子类可以直接使用父类的静态成员(共享)
但个人认为:子类不能继承父类的静态成员。(共享并非继承)
*/
System.out.println(Tiger.location);
}
}
class Animal{
private void eat(){
System.out.println("动物要吃东西");
}
public static String location = "长隆动物园"; // 1、子类是否可以继承父类的静态成员?
}
class Tiger extends Animal{
}
4.继承后:成员变量、成员方法的访问特点
package com.day01.day8_extends_field_method;
public class Test {
public static void main(String[] args) {
//目标:理解继承后成员的访问特点: 就近原则
dog d = new dog();
d.run();
d.lookDoor();
//d.go;
d.showName();
}
}
class Animal{
public String name = "动物名";
public void run(){
System.out.println("动物会跑");
}
}
class dog extends Animal{
public String name = "狗名";
public void showName(){
String name = "局部名"; // 就近原则
System.out.println(name);
System.out.println(this.name); //指定访问当前子类对象的name
System.out.println(super.name); //指定访问当前父类对象的name
run(); //就近原则 子类的run();
super.run(); //super指定父类的run();
}
public void run(){ //方法与父类重名;有限运行子类本类的方法
System.out.println("跑的好快");
}
public void lookDoor(){
System.out.println("会看门");
}
}
跑的好快
会看门
局部名
狗名
动物名
跑的好快
动物会跑进程已结束,退出代码为 0
5.继承后:方法重写
package com.day01.day9_extends_override;
public class Test {
public static void main(String[] args) {
//目标:认识方法重写
newPhone iph = new newPhone();
iph.call();
iph.massage();
}
}
/**
* 新手机:子类
*/
class newPhone extends phone{
public void call(){
super.call(); //先用父类的基本功能
System.out.println("开始视频通话"); //再用自己的功能
}
//重写的方法
public void massage(){
super.massage();
System.out.println("发送有趣的图片");
}
}
/**
* 旧手机:父类的
*/
class phone{
public void call(){
System.out.println("可以打电话");
}
public void massage(){
System.out.println("可以发短信");
}
}
可以打电话
开始视频通话
可以发短信
发送有趣的图片进程已结束,退出代码为 0
//是放在重写后的方法上,作为重写是否正确的校验注解。 建议重写方法都加@Override注解,代码安全,优雅!
@Override
//重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
public void massage(){ }
@Override //静态方法不能被重写
6.继承后:子类构造器的特点
package com.day01.day10_extends_comstructor;
public class Dog extends Animal{
public Dog() {
System.out.println("====子类Dog无参数构造器被执行====");
}
public Dog(String name) {
System.out.println("====子类Dog无参数构造器被执行====");
}
}
package com.day01.day10_extends_comstructor;
public class Animal {
public Animal(){
System.out.println("====父类Animal无参数构造器被执行====");
}
}
package com.day01.day10_extends_comstructor;
public class Test {
public static void main(String[] args) {
//目标:认识继承后子类构造器的特点
Dog d = new Dog();
//特点:子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己。
System.out.println(d);
Dog d1 = new Dog("金毛");
System.out.println(d1);
}
}
====父类Animal无参数构造器被执行====
====子类Dog无参数构造器被执行====
com.day01.day10_extends_comstructor.Dog@41629346
====父类Animal无参数构造器被执行====
====子类Dog无参数构造器被执行====
com.day01.day10_extends_comstructor.Dog@404b9385进程已结束,退出代码为 0
super(); //在子类方法中,super写不写都优先找父类的构造器
7.继承后:子类构造器访问父类有参构造器
package com.day01.day11_extends_comstructor;
public class People {
private String name;
private int age;
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = 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;
}
}
package com.day01.day11_extends_comstructor;
public class Teacher extends People{
public Teacher(String name,int age){
//调用父类的有参数构造器,初始化继承自己父类的数据
super(name,age); //不写super的话,父类有参数构造器不被继承
}
}
package com.day01.day11_extends_comstructor;
public class Test {
public static void main(String[] args) {
//目标:学习子类构造器如何去访问父类有参数构造器,还有清楚其作用。
Teacher t = new Teacher("地雷",18);
System.out.println(t.getName());
System.out.println(t.getAge());
}
}
地雷
18
进程已结束,退出代码为 0
8.this、super使用总结
package com.day01.day12_this;
public class Student {
private String name;
private String SchoolName;
public Student() {
}
/*
如果学生不填写学校,默认这个对象的学校是东京大学
*/
public Student(String name) {
//借用本类兄弟构造器
this(name,"菊花大学");
}
public Student(String name, String schoolName) {
this.name = name;
this.SchoolName = schoolName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchoolName() {
return SchoolName;
}
public void setSchoolName(String schoolName) {
this.SchoolName = schoolName;
}
}
package com.day01.day12_this;
public class Test {
public static void main(String[] args) {
//目标:理解this(...)的作用,本类构造其中访问本类兄弟构造器
Student s = new Student("周建材","菊花幼儿园");
System.out.println(s.getName());
System.out.println(s.getSchoolName());
Student s2 = new Student("周建材");
System.out.println(s2.getName());
System.out.println(s2.getSchoolName()); //悄悄地送"东京大学"
}
}
周建材
菊花幼儿园
周建材
菊花大学进程已结束,退出代码为 0
public Student(String name) {
//借用本类兄弟构造器,this也是必须在第一行
//super(); //但是在兄弟构造器中,两者不能共存
this(name,"菊花大学");
}
千里之行,始于足下