static是静态的意思,可以修饰成员变量,表示该变量只在内存中只存储一份,可以被共享访问、修改
成员变量可以分为2类
1.静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数信息等需要被共享的信息,可以被共享访问
2.实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息
public class User {
// 静态成员变量:由static修饰,属于类,加载一次,可以被共享访问
public static int onLineNumber;
// 实例成员变量,无static修饰,属于每个对象
private String name;
private int age;
public static void main(String[] args) {
User.onLineNumber ++;
// 同一个类中访问静态成员变量,类名可以省略不写
System.out.println(onLineNumber);
User u1 = new User();
u1.name = "张三";
u1.age = 32;
System.out.println(u1.name);
System.out.println(u1.age);
// 对象.静态成员变量(不推荐)
System.out.println(u1.onLineNumber);
}
}
成员方法的分类
静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问
实例成员方法(无static修饰,属于对象),只能用对象触发访问
表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法
如果该方法是执行一个通用哦那个能为目的,或者方便访问的,则可以申明成静态成员方法
public class Student {
private String name;
private int age;
public void study() {
System.out.println(name+"在学习");
}
// 静态方法 可以被类和对象共享访问
public static void getMax(int a, int b) {
System.out.println(a > b ? a : b);
}
public static void main(String[] args) {
Student s1 = new Student();
Student.getMax(10,20);
// 同一个类中访问静态成员 可以省略类名不屑
getMax(20,40);
// 实例方法
s1.name = "张三";
s1.study();
}
}
对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类
工具类的作用:一是方便调用,二是提高了代码复用
public class VerifyTool {
// 静态方法
public static String createCode(int n) {
// 1.使用String开发一个验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
// 2.定义一个变变量存储5位随机的字符作为验证码
String code = "";
// 3.循环
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(chars.length());
code += chars.charAt(index);
}
return code;
}
}
public static void main(String[] args) {
System.out.println("验证码"+ VerifyTool.createCode(5));
}
工具类原理和延申
一次编写,处处可用
建议将工具类的构造器私有,不让工具类对外产生对象
private VerifyTool() {
}
封装将数组元素拼接成字符串和求平均分工具类
public class ArrayUtils {
private ArrayUtils() {
}
public static String toString(int[] arr) {
if(arr != null) {
String result = "[";
for (int i = 0; i < arr.length; i++) {
result += i == arr.length -1 ? arr[i] : arr[i] + ",";
}
result += "]";
return result;
}
return null;
}
public static double getAverage(int[] arr) {
int max = arr[0];
int min = arr[0];
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
if(arr[i] < min) {
max = arr[i];
}
sum += arr[i];
}
return (sum - max - min) / (arr.length - 2);
}
}
public static void main(String[] args) {
int[] arr = {10,20,30};
System.out.println(arr);
System.out.println(ArrayUtils.getAverage(arr));
System.out.println(ArrayUtils.toString(arr));
}
static访问注意事项
静态方法只能访问静态的成员,不可以直接访问实例成员
实例方法可以访问静态的成员,也可以访问实例成员
静态方法中是不可以出现this关键字的
代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类),定义在类中方法外
静态代码块
格式: static {}
特点:需要通过static关键字修饰,随着类的加载而加载, 并且自动触发,只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,一遍后续使用
public class TestDemo1 {
public static String myName;
public static void main(String[] args) {
System.out.println("main方法执行输入");
System.out.println(myName);
}
/*
* 与类一起加载,自动触发一次,优先执行
* 作用 可以在程序加载时进行静态数据的初始化操作(准备内容)
* */
static {
System.out.println("静态代码块触发执行");
myName = "张三";
}
}
构造代码块(用的比较少)
格式: {}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
使用场景:初始化实例资源
public class TestDemo2 {
private String name;
/*
* 属于对象的,与对象一起加载,自动触发执行
* */
{
System.out.println("构造代码快被触发执行一次");
name = "张三";
}
public TestDemo2() {
System.out.println("构造器被触发执行");
}
public static void main(String[] args) {
TestDemo2 t1 = new TestDemo2();
System.out.println(t1.name);
TestDemo2 t2 = new TestDemo2();
System.out.println(t2.name);
}
}
案例:斗地主游戏
在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据
public class StativCodeTest3 {
/*
* 模拟斗地主牌初始化操作
* 准备一个容器,存储54张牌对象,这个容器建议使用静态的集合,静态的集合只会加载一次
* 点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
花色: "♠", "♥", "♣", "♦"
* */
static ArrayList<String> cards = new ArrayList<>();
/*
* 在游戏启动之前需要准备好54张牌放进去,使用静态代码块进行初始化
* */
static {
// 加载54张牌
// 准备4中花色
String[] colors = {"♠", "♥", "♣", "♦"};
// 定义点数
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
for (int i = 0; i < sizes.length; i++) {
for (int j=0; j<colors.length;j++) {
cards.add(sizes[i] + colors[j]);
}
}
cards.add("小王");
cards.add("大王");
}
public static void main(String[] args) {
System.out.println("新牌"+cards);
}
}
什么事设计模式
设计模式是一套被前人反复使用、多数人知晓、经过分类编目的代码设计经验的总结,后来者可以直接拿来解决问题
设计模式是软件设计中的常见解决方案,好的设计模式可以进一步的提高代码的重用性
单例模式:可以保证系统中,应用该模式的这个类只用只有一个实例,即一个类永远只能创建一个对象
单例的场景和作用
例如任务管理器对象只需要一个就可以解决问题了,这样可以节省内存空间
饿汉单例设计模式
在用类获取对象的时候,对象已经提前创建好了
设计步骤
定义一个类,把构造器私有
定义一个静态变量存储一个对象
public class SingleInstance1 {
// 2.定义一个公开的静态的成员变量村粗一个类的对象
// 饿汉:在这里加载静态变量的时候就会创建对象了
public static SingleInstance1 instance= new SingleInstance1();
// 1.把构造器私有
private SingleInstance1() {
}
}
public class Test {
public static void main(String[] args) {
SingleInstance1 s1 = SingleInstance1.instance;
SingleInstance1 s2 = SingleInstance1.instance;
SingleInstance1 s3 = SingleInstance1.instance;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)
定义一个类,把构造器私有
定义一个静态变量存储一个对象
提供一个返回单例对象的方法
public class SingleInstance2 {
// 2.创建一个静态的成员变量存储本类的对象,注意:不能初始化对象
private static SingleInstance2 instance;
// 1.私有构造器
private SingleInstance2() {
}
// 3.定义一个方法,让其他地方可以调用获取一个对象
public static SingleInstance2 getInstance() {
if(instance == null) {
// 第一次获取对象
instance = new SingleInstance2();
}
return instance;
}
}
public class Test2 {
public static void main(String[] args) {
SingleInstance2 s1 = SingleInstance2.getInstance();
SingleInstance2 s2 = SingleInstance2.getInstance();
SingleInstance2 s3 = SingleInstance2.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
继承是类与类之间的一种关系
多个类继承单独的某个类,多个类就可以使用单独的这个类的属性和行为了
多个类称为子类(派生类),单独的这个类称为父类(基类或超类)
在Java中,继承的关键字用的是extends
public class 子类名 extends 父类名{}
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 class Student extends People{
public void study() {
System.out.println("学生在学习");
}
}
public class Teacher extends People{
public void teach() {
System.out.println("老师在教书育人");
}
}
public class Test {
public static void main(String[] args) {
Teacher t = new Teacher();
Student s = new Student();
t.setName("张三");
t.setAge(20);
s.setName("lisi");
s.setAge(49);
System.out.println(t.getName());
System.out.println(t.getAge());
System.out.println(s.getName());
System.out.println(s.getAge());
}
}
提高代码复用,减少代码冗余,增强类的功能扩展性
Java中子类更强大
子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的属性和行为应该定义在子类自己里面
如果子类的独有属性、行为定义在夫类中,会导致其他子类也会得到这些属性和行为,这不符合面向对象逻辑
案例:继承的设计规范
在教育管理系统中,存在学生、老师角色
学生信息和行为(名称,年龄,所在班级,查看课表,填写听课反馈)
老师信息和行为(名称,年龄,部门名称,查看课表,发布问题)
定义角色类作为父类包含属性(名称,年龄)行为(查看课表)
public class Role {
private String name;
private int age;
public void queryCourse() {
System.out.println(name+ "查看课程信息");
}
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 class Teacher extends Role{
private String department;
public void queryQustuin() {
System.out.println(getName() + "在发布问题");
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
public class Studet extends Role{
private String className;
public void wtiteInfo() {
System.out.println(getName() + "学习中");
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("张三");
s.setAge(20);
s.setClassName("软件工程");
s.wtiteInfo();
System.out.println(s.getAge());
System.out.println(s.getClassName());
System.out.println(s.getName());
s.queryCourse();
Teacher t = new Teacher();
t.setAge(44);
t.setName("lisi");
t.setDepartment("前端部");
t.queryQustuin();
System.out.println(t.getAge());
System.out.println(t.getName());
System.out.println(t.getDepartment());
}
}
1.子类可以继承父类的属性和行为,但是子类不能继承父类的构造器
子类不可以继承父类的构造器,父类构造器用于初始化父类对象
子类可以继承父类的私有成员,不能直接访问
子类可以直接使用父类的静态成员
public class ExtendsDemo {
public static void main(String[] args) {
Student s = new Student();
// System.out.println(s.age);
// s.run();
System.out.println(Student.onLineNumber);
Student.study();
}
}
class People {
private int age = 20;
public static int onLineNumber = 122;
public static void study() {
System.out.println("学习");
}
private void run() {
System.out.println("跑");
}
}
class Student extends People{}
2.Java是单继承模式:一个类只能继承一个直接父类
3.Java不支持多继承,但是支持多层继承
4.Java中所有类都是Object类的子类
Java中所有类,要么直接继承了Object,要么默认继承了Object,要么间接继承了Object,Object是祖宗类
在子类方法中访问成员(成员变量、成员方法)满足就近原则
先子类局部范围,然后子类成员范围,然后父类成员范围找,如果父类范围还没找到就会报错
如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类需要在子类中使用中转方法,并且在中转方法中通过super调用
public class ExtendsDemo {
public static void main(String[] args) {
Student s = new Student();
System.out.println(s.name);
s.showName();
s.run();
s.go();
}
}
class People {
public String name = "人类";
public void run() {
System.out.println("人类可以跑");
}
}
class Student extends People{
public String name = "学生";
public void showName() {
String name = "局部名称";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void run() {
System.out.println("学生可以跑");
}
public void go() {
super.run();
}
}
在继承体系中,子类出现了和父类中一摸一样的方法声明,就称子类这个是重写的方法
应用场景
当子类需要父类的功能,但父类的该方法不完全满足自己的需求
子类可以重写父类中的方法
@Override重写注释
@Override是放在重写后的方法上,作为重写是否正确的校验注解
加上该注释后如果重写错误,编译阶段会出现错误提示
建议重写方法都加上@Override注解,代码安全,优雅
方法重写注意事项和要求
重写方法的名称、形参列表必须与被重写方法的一致
私有方法不能重写
子类重写父类方法时,访问权限必须大于或者等于父类(缺省
public class Phone {
public void call() {
System.out.println("打电话");
}
public void sendMessage() {
System.out.println("发短信");
}
}
public class NewPhone extends Phone{
// 方法重写
@Override
public void call() {
super.call();
System.out.println("支持视频通话");
}
@Override
public void sendMessage() {
super.sendMessage();
System.out.println("支持语音输入");
}
}
public class Test {
public static void main(String[] args) {
NewPhone n = new NewPhone();
n.call();
n.sendMessage();
}
}
子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类无法使用父类的数据
子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化
子类构造器的第一行语句默认 super() ; 默认找父类无参构造器
子类访问父类有参构造器
super调用父类有参构造器的作用:初始化继承自父类的数据
如果父类中没有无参构造器,只有有参构造器会报错,因为子类默认是调用父类无参构造器的
子类构造器中可以通过书写super(…), 手动调用父类的有参构造器
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;
}
}
public class Student extends People{
private String clssName;
public Student(String name, int age, String clssName) {
super(name, age);
this.clssName = clssName;
}
public String getClssName() {
return clssName;
}
public void setClssName(String clssName) {
this.clssName = clssName;
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student("zhansgan", 20, "软件工程");
System.out.println(s.getClssName());
}
}
this代表本类对象的引用 super:代表父类存储空间的标识
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 |
this.成员方法(…) 访问本类成员方法 |
this(…) 访问本类构造器 |
super | super.成员变量 访问父成员变量 |
super.成员方法(…) 访问父类成员方法 |
super(…) 访问父类构造器 |
案例:在管理系统中,后台创建对象封装数据的时候如果用户没有输入年龄,则默认为20,如果输入则为输入的数据
this(…)和super(…)使用注意点:
子类通过this(…)去调用本类的其他构造器,本类其他构造器会通过super去手动调用父类的构造器,最终韩式会调用父类构造器的
注意:this(…)super(…)都只能放在构造器的第一行,所以二者不能共存在同一个构造器中
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name) {
// 借用兄弟构造器
this(name, 20);
}
public Student(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;
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三", 12);
System.out.println(s1.getAge());
System.out.println(s1.getName());
Student s2 = new Student("李四");
System.out.println(s2.getAge());
System.out.println(s2.getName());
}
}