需要学习哪些语法?
static静态关键字 :之前定义的成员变量:name,age属于每个对象的。如何表示共享的信息?如在线人数等
继承 :有些类只需要一个对象就可以了,如任务管理器对象,如何实现一个类只能对外产生一个对象?
多态 :系统中很多实体类的属性和行为存在重复代码,如何把这些类信息进行优化,降低代码冗余,提升代码复用呢?
static静态关键字 修饰成员变量的用法
static是什么
static是静态 的意思,可以用来修饰成员变量、成员方法。
static修饰成员变量之后称为静态成员变量(类变量) ,修饰方法之后称为静态方法(类方法) 。
static修饰后的成员变量,可以被类的所有对象共享(访问、修改) 。
1 2 3 4 public class User { static String name; int age; }
修饰成员变量的内存原理
static修饰的成员变量是什么? 有什么特点?
静态成员变量(有static修饰,属于类、加载一次,内存中只有一份),访问格式:1 2 类名.静态成员变量(推荐) 对象.静态成员变量(不推荐)
实例成员变量(无static修饰,属于对象),访问格式:
两种成员变量各自在什么情况下定义?
静态成员变量:表示在线人数等需要被类的所有对象共享的信息时。
实例成员变量:属于每个对象,且每个对象的该信息不同时(如:name,age,money…)
修饰成员变量的应用:在线人数统计 略。
修饰成员方法的用法
修饰成员方法的内存原理
修饰成员方法的应用:工具类 略(见下文)。
练习:定义员工类的实例
需求:请完成一个标准实体类的设计,并提供如下要求实现。
某公司的员工信息系统中,需要定义一个公司的员工类Employee,包含如下信息(name, age , 所在部门名称dept ) , 定义一个静态的成员变量company记录公司的名称。
需要在Employee类中定义一个方法showInfos(),用于输出当前员工对象的信息。如name, age ,dept 以及公司名称company的信息。
需要在Employee类中定义定义一个通用的静态方法compareByAge,用于传输两个员工对象的年龄进入,并返回比较较大的年龄,例如:2个人中的最大年龄是:45岁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package study;public class Employee { private String name; private int age; private String deptName; public static String companyName; public void showInfos () { System.out.println("姓名:" + name + "," + "年龄:" + age + "," + "部门名称:" + deptName + "," + "公司名称:" + companyName); } public static int compareByAge (int a, int b) { return a > b ? a : b; } public Employee () { } public Employee (String name, int age, String deptName) { this .name = name; this .age = age; this .deptName = deptName; } 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 getDeptName () { return deptName; } public void setDeptName (String deptName) { this .deptName = deptName; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package study;public class EmployeeTest { public static void main (String[] args) { Employee employee1 = new Employee("周星驰" , 30 , "表演部" ); Employee.companyName = "星辉传媒" ; System.out.println(Employee.companyName); employee1.showInfos(); Employee employee2 = new Employee("吴孟达" ,45 ,"表演部" ); Employee.companyName = "佳丽传媒" ; System.out.println(Employee.companyName); employee2.showInfos(); int maxAge = Employee.compareByAge(employee1.getAge(), employee2.getAge()); System.out.println("最大年龄是:" +maxAge); } }
星辉传媒 姓名:周星驰,年龄:30,部门名称:表演部,公司名称:星辉传媒 佳丽传媒 姓名:吴孟达,年龄:45,部门名称:表演部,公司名称:佳丽传媒 最大年龄是:45
注意事项 static访问注意事项:
静态方法只能访问静态的成员,不可以直接访问实例成员。
实例方法可以访问静态的成员,也可以访问实例成员。
静态方法中是不可以出现this关键字的。
static应用知识:工具类 工具类的好处、要求
工具类是什么? 类中都是一些静态方法 ,每个方法都是以完成一个共用的功能 为目的,这个类用来给系统开发人员共同使用的。
案例导学: 在企业的管理系统中,通常需要在一个系统的很多业务处使用验证码进行防刷新等安全控制。
问题: 同一个功能多处开发,会出现代码重复度过高。
使用工具类的好处 一是调用方便,二是提高了代码复用(一次编写,处处可用)
为什么工具类中的方法不用实例方法做? 实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存。
工具类是什么,有什么好处?
内部都是一些静态方法,每个方法完成一个功能
一次编写,处处可用,提高代码的重用性。
工具类定义时有什么要求? 有些工具类只有静态方法 ,不需要创建实例对象,建议将工具类的构造器私有化处理,避免实例化。
练习:定义数组工具类
需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils
我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10, 20, 50, 34, 100](只考虑整数数组,且只考虑一维数组 )
经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组 )
定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package study;public class ArraysUtils { private ArraysUtils () { } public static String toString (int [] arr) { String arrToStr = "[" ; for (int i = 0 ; i < arr.length; i++) { if (i == arr.length - 1 ) { arrToStr += arr[i] + "]" ; } else { arrToStr += arr[i] + ", " ; } } return arrToStr; } public static double getAerage (double [] arr) { if (arr == null ) { System.out.println("数组为空" ); return -1 ; } if (arr.length < 3 ){ System.out.println("数组长度过短" ); return -1 ; } double sum = 0 , max = arr[0 ], min = arr[0 ]; for (int i = 0 ; i < arr.length; i++) { sum += arr[i]; if (max < arr[i]) { max = arr[i]; } if (min > arr[i]) { min = arr[i]; } } return (sum - max - min) / (arr.length - 2 ); } }
1 2 3 4 5 6 7 8 9 10 public class ArraysUtilsTest { public static void main (String[] args) { int [] arr1 = {1 , 3 , 5 , 7 , 9 , 11 }; double [] arr2 = {1.56 , 2.67 , 2.7 , 6.99 , 3.58 , 1.07 , 3.6 }; System.out.println(ArraysUtils.toString(arr1)); System.out.println(ArraysUtils.getAerage(arr2)); } }
static应用知识:代码块 代码块的分类、作用
代码块概述
代码块是类的5大成分之一(成员变量、构造器,方法,代码块 ,内部类),定义在类中方法外。
在Java类下,使用 { }
括起来的代码被称为代码块 。
代码块分为:
静态代码块的应用案例:斗地主
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package demo3;public class Card { private String number; private String color; private int index; public Card () { } public Card (String number, String color, int index) { this .number = number; this .color = color; this .index = index; } public String getNumber () { return number; } public void setNumber (String number) { this .number = number; } public String getColor () { return color; } public void setColor (String color) { this .color = color; } public int getIndex () { return index; } public void setIndex (int index) { this .index = index; } @Override public String toString () { return "Card{" + "number='" + number + '\'' + ", color='" + color + '\'' + ", index=" + index + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package demo3;import java.util.ArrayList;import java.util.Collections;public class CardTest { public static ArrayList<Card> cards = new ArrayList<>(); static { String[] nums = {"3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "J" , "Q" , "K" , "A" , "2" }; String[] colors = {"♠" , "♥" , "♣" , "♦" }; int index = 0 ; for (String num : nums) { for (String color : colors) { Card card = new Card(num, color, index++); cards.add(card); } } cards.add(new Card("14" , "🃏" , index++)); cards.add(new Card("15" , "🃏" , index++)); System.out.println("新牌是:" + cards); Collections.shuffle(cards); System.out.println("洗牌后:" + cards); } public static void main (String[] args) { ArrayList<Card> p1 = new ArrayList<>(); ArrayList<Card> p2 = new ArrayList<>(); ArrayList<Card> p3 = new ArrayList<>(); for (int i = 0 ; i < cards.size() - 3 ; i++) { if (i % 3 == 0 ) { p1.add(cards.get(i)); } if (i % 3 == 1 ) { p2.add(cards.get(i)); } if (i % 3 == 2 ) { p3.add(cards.get(i)); } } ArrayList<Card> lastCards = new ArrayList<>(); lastCards.add(cards.get(cards.size() - 3 )); lastCards.add(cards.get(cards.size() - 2 )); lastCards.add(cards.get(cards.size() - 1 )); System.out.println("p1的牌:" + p1); System.out.println("p2的牌:" + p2); System.out.println("p3的牌:" + p3); System.out.println("底牌:" + lastCards); } }
static应用知识:单例 略。
面向对象三大特征之二:继承 继承的概述、好处
设计规范、内存运行原理
案例:继承的设计规范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package demo4;public class People { private String name; private int age; public void viewTimetable () { 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; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package demo4;public class Student extends People { private String className; public void write () { System.out.println(getName() + "正在填写听课反馈" ); } public Student () { } public String getClassName () { return className; } public void setClassName (String className) { this .className = className; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package demo4;public class Teacher extends People { private String deptName; public void releaseQuestions () { System.out.println(getClass() + "发布了一个课堂作业" ); } public Teacher () { } public String getDeptName () { return deptName; } public void setDeptName (String deptName) { this .deptName = deptName; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package demo4;public class Test { public static void main (String[] args) { Student student = new Student(); student.setName("李狗蛋" ); student.setAge(23 ); student.setClassName("计算机1班" ); System.out.println(student.getName()); System.out.println(student.getAge()); System.out.println(student.getClassName()); student.write(); student.viewTimetable(); } }
内存运行原理
继承的特点
继承的特点
子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。
Java是单继承 模式:一个类只能继承一个直接父类。
Java不支持多继承、但是支持多层继承 。
Java中所有的类都是Object类的子类。Java中所有类,要么直接继承了Object , 要么默认继承了Object , 要么间接继承了Object, Object是祖宗类。
继承后:成员变量、成员方法的访问特点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package demo5;public class Test { public static void main (String[] args) { Zi z = new Zi(); z.ziShow(); } } class Fu { String name = "父类成员变量" ; } class Zi extends Fu { String name = "子类成员变量" ; public void ziShow () { String name = "子类成员方法局部变量" ; System.out.println(name); System.out.println(this .name); System.out.println(super .name); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package demo5;public class Test { public static void main (String[] args) { Zi z = new Zi(); z.ziShow(); } } class Fu { String name = "父类成员变量" ; String hobby = "钓鱼" ; } class Zi extends Fu { String name = "子类成员变量" ; String hobby = "吃鸡" ; public void ziShow () { System.out.println(this .name); System.out.println(name); System.out.println(this .hobby); System.out.println(hobby); System.out.println(super .name); System.out.println(super .hobby); } }
继承后:方法重写
联系一下之前学的“方法重载”,那个指的是在同一个类中方法名一样但参数不一样。 但“方法重写”的名称和形参列表应该与被重写方法一致。
什么是方法重写? 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
方法重写的应用场景 当子类需要父类的功能,但父类的该功能不完全满足自己的需求时。子类可以重写父类中的方法。
案例演示:
旧手机的功能只能是基本的打电话,发信息
新手机的功能需要能够:基本的打电话下支持视频通话。基本的发信息下支持发送语音和图片。
@Override重写注解
@Override是放在重写后的方法上,作为重写是否正确的校验注解。
加上该注解后如果重写错误,编译阶段会出现错误提示。
建议重写方法都加@Override注解,代码安全,优雅!
方法重写注意事项和要求
重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
私有方法不能被重写。
子类重写父类方法时,访问权限必须大于或者等于父类 (暂时了解 :private < 缺省 < protected < public
)
子类不能重写父类的静态方法,如果重写会报错的。
方法重写是什么样的?
方法重写建议加上哪个注解,有什么好处? @Override注解可以校验重写是否正确,同时可读性好。
重写方法有哪些基本要求?
重写方法的名称和形参列表应该与被重写方法一致。
私有方法不能被重写。
子类重写父类方法时,访问权限必须大于或者等于父类被重写的方法的权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package demo5;public class Test02 { public static void main (String[] args) { Student s = new Student(); s.lunch(); } } class Person { public void eat () { System.out.println("吃大米饭" ); } public void drink () { System.out.println("喝开水" ); } } class Student extends Person { @Override public void eat () { System.out.println("吃黄焖鸡米饭" ); } @Override public void drink () { System.out.println("喝奶茶" ); } public void lunch () { eat(); drink(); this .eat(); this .drink(); super .eat(); super .drink(); } }
继承后:子类构造器的特点
继承后:子类构造器访问父类有参构造器
super调用父类有参数构造器的作用: 通过调用父类有参数构造器来初始化继承自父类的数据
如果父类中没有无参数构造器,只有有参构造器,会出现什么现象呢? 会报错。因为子类默认是调用父类无参构造器的。
如何解决? 子类构造器中可以通过书写 super(…),手动调用父类的有参数构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package demo6;public class Person { private String name; private int age; public Person () { } public Person (String name, int age) { this .name = name; this .age = age; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package demo6;public class Student extends Person { String className; public Student () { super (); } public Student (String className) { this .className = className; } public Student (String name, int age, String className) { super (name, age); this .className = className; } }
this、super使用总结
this
:代表本类对象的引用;
super
:代表父类存储空间的标识。
关键字
访问成员变量
访问成员方法
访问构造方法
this
this.成员变量 访问本类成员变量
this.成员方法 访问本类成员方法
this(…) 访问本类构造器
super
super.成员变量 访问父类成员变量
super.成员方法 访问父类成员方法
super(…) 访问父类构造器
案例练习:
上方表格中,只有this.(...)
访问本地构造器我们还没学,用一个例子练一下
在学员信息登记 系统中,后台创建对象封装数据的时候如果用户没有输入学校 ,则默认使用“河南师范大学”。
如果用户输入了学校则使用用户输入的学校信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package demo7;public class Student { private String schoolName; private String name; public Student () { } public Student (String name, String schoolName) { this .name = name; this .schoolName = schoolName; } public Student (String name) { this (name, "河南师范大学" ); } }
this(…)和super(…)使用注意点:
子类通过 this(…)
去调用本类的其他构造器,本类其他构造器会通过 super 去手动调用父类的构造器,最终还是会调用父类构造器的。
注意:this(…)
super(…)
都只能放在构造器的第一行,所以二者不能共存在同一个构造器中。
面向对象三大特征之三:多态
面向对象三大特征有封装
:把一些静态属性 或动态方法 封装起来成为一个对象继承
:解决了封装重复的问题,减小了代码的冗余多态
多态的概述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package demo8;public class Person { private String name; private int age; public void show () { System.out.println(name + ", " + age); } public Person () { } public Person (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; } }
1 2 3 4 5 6 7 8 9 10 package demo8;public class Student extends Person { @Override public void show () { super .show(); System.out.println("学生的信息为:" + getName() + "," + getAge()); } }
1 2 3 4 5 6 7 8 9 10 package demo8;public class Teacher extends Person { @Override public void show () { super .show(); System.out.println("老师的信息为:" + getName() + "," + getAge()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package demo8;public class Test { public static void main (String[] args) { Student student = new Student(); student.setName("张三" ); student.setAge(19 ); Teacher teacher = new Teacher(); teacher.setName("王老师" ); teacher.setAge(43 ); register(student); register(teacher); } public static void register (Person p) { p.show(); } }
张三, 19 学生的信息为:张三,19 王老师, 43 老师的信息为:王老师,43
多态的优势
在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
1 2 Peoson p = new Student(); p.show();
定义方法的时候,使用父类型作为参数 ,该方法就可以接收这父类的一切子类对象 ,体现出多态的扩展性与便利。
多态下会产生的一个问题: 多态下不能使用子类的独有功能 ,只能使用子类中的重写方法
多态下: 类型转换问题 自动类型转换(从子到父)向上转型: 1 2 Peoson p = new Student(); p.eat();
强制类型转换(从父到子)向下转型:
从父到子(必须进行强制类型转换,否则报错): 子类 对象变量 = (子类)父类类型的变量
作用:可以解决多态下的劣势,可以实现调用子类独有的功能。
注意:有继承/实现关系的类就可以在编译阶段进行强制类型转换。1 2 Peoson p = new Student(); Student s = (Student)p;
如果转型后的类型 和对象真实的类型不是同一种类型 ,那么在运行代码时,就会出现ClassCastException
(类强制转换异常)1 2 3 4 5 Peoson p = new Student(); Teacher p = (Teacher)p;
Java建议强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换。判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之返回false。
用一个案例理解一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package demo9;public class Test { public static void main (String[] args) { Animal a = new Dog(); a.eat(); Dog d = (Dog) a; d.lookHome(); } } class Animal { public void eat () { System.out.println("动物吃东西" ); } } class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } public void catchMouse () { System.out.println("猫的工作是抓老鼠" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } public void lookHome () { System.out.println("狗看家" ); } }
建议强制转换前使用instanceof判断类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package demo9;public class Test { public static void main (String[] args) { Cat a = new Cat(); show(a); Dog d = new Dog(); show(d); } public static void show (Animal a) { a.eat(); if (a instanceof Dog){ Dog d = (Dog) a; d.lookHome(); }else if (a instanceof Cat){ Cat c = (Cat) a; c.catchMouse(); }else { System.out.println("没有这个类型,无法转换" ); } } } class Animal { public void eat () { System.out.println("动物吃东西" ); } } class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } public void catchMouse () { System.out.println("猫的工作是抓老鼠" ); } } class Dog extends Animal { @Override public void eat () { System.out.println("狗吃骨头" ); } public void lookHome () { System.out.println("狗看家" ); } }
引用数据类型的类型转换,有几种方式?
强制类型转换能解决什么问题?
强制类型转换需要注意什么?
有继承关系/实现的2个类型就可以进行强制转换,编译无问题。
运行时,如果发现强制转换后的类型不是对象真实类型则报错(ClassCastException)
强制类型转换前最好做什么事情,如何进行?
使用instanceof判断当前对象的真实类型,再进行强制转换
对象变量名 instanceof 真实类型
多态的综合案例
1 先暂时不做,该案例好像以及超出多态的范围了,涉及接下来要讲的接口
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 百里飞洋 ! 技术内容: 若存在错误或不当之处,还望兄台不吝赐教,期待与您交流!