知识点1:多态的理解
- 开发中多态的常见场景
public static void main(String[] args) {
//开发中很少见的多态场景
Person p1 = new Man();
System.out.println(p1.id);//属性不存在多态性
p1.eat();
// p1.earnMoney();
PersonTest test = new PersonTest();
test.method(new Man());//开发中常见的多态的场景
}
public void method(Person p) { //Person p = new Man();
p.eat();
p.walk();
System.out.println(p.id);
}
- 有了多态之后,编译、运行中出错的情况展示
//###########更多的开发常见问题###################
//编译不通过
// Woman w1 = (Woman)new Man();
// String str = new Date();
//编译通过,运行不通过
// Person p2 = new Man();
// Woman w2 = (Woman)p2;
// Object obj = new Date();
// String str = (String)obj;
Person p2 = new Person();
Man m2 = (Man) p2;
//编译通过,运行也通过
Object obj = new Man();
Person p3 = (Person) obj;
p3.eat();
面试题:如何理解面向对象的三大特征?
使用自己的语言组织
尽量多举开发中的例子
知识点2:Object类
1. 理解
* 1. java.lang.Object是所有其他java类的根父类
* 内部声明的方法具有通用性。
*
* 2. clone():可以看做是创建Java中对象的第二种方式
* 3. finalize():当垃圾回收器在回收对象前,对象会调用此方法。
面试题:final \ finally \ finalize 三者的区别
4. hashCode():放到后面集合内容讲解
5. wait() / notify() / notifyAll() :放到后面线程通信时讲解
2. equals()的使用
java.lang.Object类的equals()的使用
*
* 1. java.lang.Object类中equals()的声明:
* public boolean equals(Object obj) {
* return (this == obj);
* }
* 说明:Object类中的equals()是比较两个对象的地址值是否相同。(或比较两个引用是否指向堆空间中的同一个对象)
*
* 2. 像String\File\Date类等都重写了Object类中的equals()。重写的规则:
* 比较两个对象的属性值是否都相等。
*
* 3. 自定义类在没有重写Object类的equals()前,比较的都是两个引用的地址值是否相等。
* 但是一般开发中,凡是调用了equals(),都是想比较两个对象的实体内容是否相等。则意味着我们
* 要重写equals().
- 举例
public class Order {
private String orderName;
private int orderId;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public Order(String orderName, int orderId) {
this.orderName = orderName;
this.orderId = orderId;
}
public Order() {
}
//手动重写equals():比较两个对象的实体内容是否相等。
// @Override
// public boolean equals(Object obj) {
// System.out.println("Order equals()....");
// if (this == obj) {
// return true;
// }
// if (obj instanceof Order) {
// Order order = (Order) obj;
// //比较当前Order对象this与order对象的实体内容
if(this.orderId == order.orderId && this.orderName.equals(order.orderName)){
return true;
}else{
return false;
}
// //可以写为:
// return this.orderId == order.orderId && this.orderName.equals(order.orderName);
// }
//
// return false;
//
// }
//自动生成的equals()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Order order = (Order) o;
if (orderId != order.orderId) return false;
return orderName != null ? orderName.equals(order.orderName) : order.orderName == null;
}
}
- 面试题:
面试题: == 和 equals() 的区别?
1. == : 运算符,适用于基本数据类型(比较两个数据的值是否相等)、引用数据类型(比较两个引用是否指向堆空间中的同一个对象)
2. equals(): 适用于引用数据类型。
3. toString()的使用
1. Object类中toString()的定义:
* public String toString() {
* return getClass().getName() + "@" + Integer.toHexString(hashCode());
* }
* 2. 当我们没有重写Object类中的toString()方法时,当输出对象的引用时,默认调用Object类
* 中的toString()方法,输出对象的地址值。
*
* 3. 像String\日期Date\File类等类型都重写了Object类中的toString()方法,返回其内部的
* 实体内容。
*
* 4. 如果我们希望调用自定义类的toString()时,希望返回其内部实体内容。则需要进行重写。
*
- 举例
package com.atguigu.java1;
/**
* @author shkstart
* @create 2020-07-07 10:42
*/
public class Order {
private String orderName;
private int orderId;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public Order(String orderName, int orderId) {
this.orderName = orderName;
this.orderId = orderId;
}
public Order() {
}
//手动生成的:
// public String toString() {
// return "Order[orderName : " + orderName + ",orderId : " + orderId + "]";
// }
//自动生成的:
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
'}';
}
}
知识点3:包装类的使用
1. 我们为8种基本数据类型提供了对应的8种包装类。目的是为了让基本数据数据类型的变量
* 具备类的特征 ---> 便于一些方法调用时使用。
2. 掌握8种基本数据类型以及对应的包装类。
3. 掌握:基本数据类型、包装类、String类三者之间的转换操作
- 测试举例
/*
基本数据类型---> 对应的包装类:
包装类 ---> 基本数据类型:
*/
@Test
public void test1(){
//基本数据类型---> 对应的包装类:调用包装类的构造器
int m = 10;
Integer integer1 = new Integer(m);
System.out.println(integer1.toString());
float f1 = 10.2F;
Float float1 = new Float(f1);
String s1 = "10.3";
Float float2 = new Float(s1);
System.out.println(float2.toString());
//包装类 ---> 基本数据类型:调用包装类的xxxValue()
int j = integer1.intValue();
System.out.println(j + 0);
float f2 = float2.floatValue();
}
//JDK5.0引入的新特性:自动的装箱和拆箱
@Test
public void test2(){
int m = 10;
Integer int1 = m;//自动装箱
Integer int2 = 10;//自动装箱
System.out.println(int1.toString());
method(10);//自动装箱
int n = int1;//自动拆箱
int sum = int1 * 20;//自动拆箱
test1(int2);//自动拆箱
}
public void method(Object obj){
System.out.println(obj);
}
public void test1(int i){
}
/*
基本数据类型、包装类 --> String类型:
String类型 ---> 基本数据类型、包装类:
*/
@Test
public void test3(){
//基本数据类型、包装类 --> String类型: ① 调用String重载的valueOf(Xxx xx) ② 连接符:+
int num = 10;
Float f1 = new Float(10.1);
String s1 = String.valueOf(num);
String s2 = String.valueOf(f1);
System.out.println(s1);
System.out.println(s2);
String s3 = num + "";
}
@Test
public void test4(){
String s1 = "123";
// s1 = "123abc";//会报NumberFormatException
// String类型 ---> 基本数据类型、包装类:调用包装类Xxx的parseXxx()
Integer int1 = new Integer(s1);
int i = Integer.parseInt(s1);
String s2 = "true123";
s2 = "TruE";
boolean b = Boolean.parseBoolean(s2);
System.out.println(i);
System.out.println(b);
}
}
- 简化为:
JDK5.0引入的新特性:自动的装箱和拆箱.可以实现基本数据类型和包装类之间的转换
基本数据类型、包装类 --> String类型: ① 调用String重载的valueOf(Xxx xx) ② 连接符:+
String类型 ---> 基本数据类型、包装类:调用包装类Xxx的parseXxx()
- 补充说明
class Order{
boolean isMale;
Boolean isMarried;
}
class Account{
double balance;//0.0
Double balance1;//null
}
//测试时:
@Test
public void test5(){
Order order = new Order();
System.out.println(order.isMale);//false
System.out.println(order.isMarried);//null
}
知识点4:单元测试方法
/**
* 单元测试方法的使用
*
* 1. 为什么使用单元测试方法:为了方便的在测试类中针对多个不同的代码或方法单独进行测试。
*
* 2. 如何实现?有什么要求?
* ① 单元测试方法声明前加上注解: @Test (来自于org.junit.Test)
* ② 单元测试方法是:public的、无返回值类型的、无形参的方法
* ③ 单元测试类是public的,提供空参的public权限的构造器
*
* 如果以上条件不满足,在执行单元测试方法时,报initializationError
*
* @author shkstart
* @create 2020-07-07 15:22
*/
public class JUnitTest { //单元测试类
@Test
public void test1(){ //单元测试方法
System.out.println("hello");
int m = 10;
int n = 20;
System.out.println( m + n);
}
@Test
public void test2(){
int m1 = 10;
int n1 = 10;
System.out.println(m1 == n1);//true
int m2 = 65;
char c1 = 'A';
System.out.println(m2 == c1);//true
float f1 = 65.0F;
System.out.println(m2 == f1);//true
}
@Test
public void testGet(){
int sum = get(10,20);
System.out.println(sum);
}
public int get(int m,int n){
return m + n;
}
}
补充:关于String字符串常量池的使用
public class StringTest {
public static void main(String[] args) {
//通过字面量的方式进行字符串的赋值操作。此时的字符串数据保存在字符串常量池中。
//字符串常量池中,不存在内容相同的字符串。
String s1 = "hello";//字面量赋值的方式
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1.equals(s2));//true
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
}
}
6_面向对象-下
知识点1:static关键字
static关键字的使用
*
* 1. static:静态的
* 2. 可以用来修饰:属性、方法、内部类、代码块
*
* 3. 使用static修饰属性:
*
* 3.1 回顾变量按照在类中声明的位置来分:
* 成员变量(属性):
* 类变量(或静态变量)
* 实例变量(或非静态变量)
* 局部变量:
* 方法内、构造器内、代码块内定义的
* 方法形参、构造器形参
* 3.2 非静态属性的特点:
* 每当我们创建一个类的实例,内存中就会在堆空间里分配一套类的非静态变量。类的多个实例的相同属性之间
* 没有任何关系。
* 3.3 静态属性的特点:
* ① 类的多个实例共享类的静态属性
* ② 类的静态属性在内存中就只有一份。存在于方法区的静态域中。
* ③ 类的静态属性随着类的加载而加载。
* (对比:类的非静态属性随着对象的创建而加载)
* ④ 静态属性 非静态属性
* 类 yes no
* 对象 yes yes
* ⑤ 当通过一个对象修改静态属性时,会导致其它对象对此静态属性的调用。
*
* 4. 使用static修饰方法:
* ① 随着类的加载而加载
* ② 静态方法 非静态方法
* 类 yes no
* 对象 yes yes
* ③ 静态方法内只能调用静态的属性、静态的方法。不能调用非静态的结构:属性、方法
* 非静态的方法内可以调用静态的结构或非静态的结构:属性、方法
*
*
* 5. 什么情况下适合将属性声明为static的?
* ① 当一个类的多个对象关于某一属性的值都是相同时,可以声明为static的。即:没有必要
* 给每个对象分配一份此属性的值时。
* ② 工具类中的属性通常都是静态的。
*
* 什么情况下适合将方法声明为static的?
* ① 通常操作静态属性的方法设置为静态的。(比如:get和set方法)
* ② 工具类中的方法通常都是静态方法
*
- 代码演示
public class StaticTest {
public static void main(String[] args) {
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 38;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "刘翔";
c2.age = 35;
c2.nation = "中国";
c1.info();
c2.info();
//使用"类.静态变量"的方式访问静态变量
System.out.println(Chinese.nation); //Math.PI
//不能使用"类.非静态变量"
// System.out.println(Chinese.name);
Chinese.show();//Math.sqrt(..),Math.random(),Math.round(..),Arrrys.sort(..)
}
}
class Chinese{
//非静态变量(或实例变量)
String name;
int age;
//静态变量(或类变量)
static String nation;
public void info(){
System.out.println("name = " + name + ", age = " + age + ", nation = " + nation);
show();
}
public static void show(){
System.out.println("我是中国人!!");
System.out.println("nation = " + nation);
//不能调用非静态的结构
// System.out.println("name = " + name);
// info();
}
}
- static的应用1
package com.atguigu.java1;
/**
* static的应用举例
* @author shkstart
* @create 2020-07-08 11:16
*/
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle(1.2);
System.out.println(c1);
Circle c2 = new Circle(2.2);
System.out.println(c2);
Circle c3 = new Circle();
System.out.println(c3);
System.out.println("创建的圆的个数为:" + Circle.getCircleInstanceCount());
}
}
class Circle{
private double radius;//半径
private int id;//编号
private static int init = 1001;
private static int circleInstanceCount;//记录创建的圆的个数
public Circle(double radius){
// this();
this.radius = radius;
this.id = init++;
circleInstanceCount++;
}
public Circle(){
this.id = init++;
circleInstanceCount++;
}
@Override
public String toString() {
return "Circle{" +
"radius=" + radius +
", id=" + id +
'}';
}
public int getId() {
return id;
}
public static int getCircleInstanceCount() {
return circleInstanceCount;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
}
- static的应用2
package com.atguigu.exer;
/**
* 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、
* “最小余额”,定义封装这些属性的方法。账号要自动生成。
* 编写主类,使用银行账户类,输入、输出3个储户的上述信息。
* 考虑:哪些属性可以设计成static属性。
* @author shkstart
* @create 2020-07-08 15:09
*/
public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account();
Account acct2 = new Account("qwerty",3000);
Account acct3 = new Account("asdfg",2000);
System.out.println(acct1);
System.out.println(acct2);
System.out.println(acct3);
}
}
class Account{
private int id ;//账号
private String password = "000000";//密码
private double balance;//存款余额
private static double interestRate;//存款利率
private static double minBalance;//最小余额
private static int init = 1000;//用于自动生成账号的属性
public Account(){
this.id = ++init;
}
public Account(String password,double balance){
this();
//this.id = ++init;
this.password = password;
this.balance = balance;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static double getInterestRate() {
return interestRate;
}
public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}
public static double getMinBalance() {
return minBalance;
}
public static void setMinBalance(double minBalance) {
Account.minBalance = minBalance;
}
public int getId() {
return id;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", password='" + password + '\'' +
", balance=" + balance +
'}';
}
}
知识点2:单例模式
- 设计模式
* 1.设计模式:是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模免去我们自己再思考和摸索。
* 就像是经典的棋谱,不同的棋局,我们用不同的棋谱。 ”套路”
*
* 经典的设计模式有23种
创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
对软件设计模式的研究造就了一本可能是面向对象设计方面最有影响的书籍:《设计模式》:《Design Patterns: Elements of Reusable Object-Oriented Software》(即后述《设计模式》一书),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。这几位作者常被称为"四人组(Gang of Four)",而这本书也就被称为"四人组(或 GoF)"书。
- 单例模式
2. 单例模式(单子模式,singleton):在整个的软件系统中,对某个类只能存在一个对象实例
*
* 3. 如何实现单例模式:
* 饿汉式、懒汉式
*
* 对比?
* 懒汉式好:延迟了对象的创建
* >有线程安全问题。
* 饿汉式好:没有线程的安全问题。
- 饿汉式
public class SingletonTest {
public static void main(String[] args) {
// Bank bank1 = new Bank();
// Bank bank1 = new Bank();
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);
}
}
//饿汉式
class Bank{
//1. 私有化类的构造器
private Bank(){
}
//2. 在类的内部创建对象
private static Bank bank = new Bank();
//3. 提供访问该对象的get方法
public static Bank getInstance(){
return bank;
}
}
- 懒汉式
/**
* 单例模式之懒汉式
*
* @author shkstart
* @create 2020-07-08 11:53
*/
public class SingletonTest1 {
public static void main(String[] args) {
Application app1 = Application.getInstance();
Application app2 = Application.getInstance();
System.out.println(app1 == app2);
}
}
class Application{
//1. 私有化类的构造器
private Application(){}
//2.声明当前类的实例
private static Application app = null;
//3. 调用方法时,根据app是否初始化,进行赋值。并返回
public static Application getInstance(){
if(app == null){
app = new Application();
}
return app;
}
}
知识点3:体会main()
/**
* main()的理解
* 1. 作为程序的入口
* 2. 可以看做是一个普通的静态方法
* 3. 除了使用Scanner之外,也可以使用main()从控制台传入需要的数据。都作为String
* 类型的变量接收。
* @author shkstart
* @create 2020-07-08 14:08
*/
public class MainDemo {
public static void main(String args[]) {
Main.main(new String[10]);
}
}
class Main{
public static void main(String[] args) {
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
- 如何在调用main()时,传参数
知识点4:类的成员之四:代码块
* 类的成员之四:代码块的使用
*
* 1. 从格式上讲,命名为:代码块
* 从功能上讲,命名为:初始化块
*
* 2.代码块的分类:静态代码块 、 非静态代码块
*
* 3. 静态代码块:
* 1. 内部可以编写执行语句
* 2. 随着类的加载而执行
* 3. 静态代码块的执行要早于非静态代码块
* 4. 静态代码块只执行一次
* 5. 如果类中定义了多个静态代码块,则按照声明的先后顺序执行
* 6. 在内部可以调用当前类中的静态结构:属性、方法。不能调用非静态的结构
* 7. 作用:用来初始化当前类的静态属性。
*
*
* 4. 非静态代码块:
* 1. 内部可以编写执行语句
* 2. 随着对象的创建而执行
* 3. 每创建一个对象,非静态代码块就执行一次
* 4. 如果类中定义了多个非静态代码块,则按照声明的先后顺序执行
* 5. 在内部可以调用当前类中的静态结构和非静态结构:属性、方法
* 6. 作用:用来初始化创建的对象的实例变量。
- 代码演示
public class BlockTest {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println();
Person p2 = new Person();
System.out.println();
Person p3 = new Person();
}
}
class Person{
String name;
int age;
static String info = "我是人类";
public void eat(){
System.out.println("吃饭");
}
public static void show(){
System.out.println("我是一个勤劳的人类");
}
public Person(){
// System.out.println("Person()....");
}
//非静态代码块
{
System.out.println("我是非静态代码块1");
//可以调用类中静态的结构
System.out.println(info);
show();
//可以调用类中静态的结构
System.out.println(name);
eat();
}
{
System.out.println("我是非静态代码块2");
}
//静态代码块
static {
System.out.println("我是静态代码块1");
//可以调用类中静态的结构
System.out.println(info);
show();
//不可以调用类中静态的结构
// System.out.println(name);
// eat();
}
static {
System.out.println("我是静态代码块2");
}
}
- 练习
//由父及子,静态先行
class Root{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root(){
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid(){
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg){
//通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:"
+ msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf(){
//通过super调用父类中有一个字符串参数的构造器
super("尚硅谷");
System.out.println("Leaf的构造器");
}
}
public class LeafTest{
public static void main(String[] args){
new Leaf();
System.out.println();
new Leaf();
}
}
知识点5:属性赋值
/**
* 1. 有哪些位置可以给类中的属性赋值? (以非静态的属性说明)
* ① 默认初始化
* ② 显式初始化 / ⑤ 代码块中初始化
* ③ 构造器中初始化
*
* ④ 创建了对象以后,通过"对象.属性"或"对象.方法"的方式给属性赋值
*
*
* 2. 赋值的先后顺序?
* ① - ②、⑤ - ③ - ④
*
* 说明:② 、 ⑤ 的执行按照声明的位置决定的。先声明的先执行。
*
*
* @author shkstart
* @create 2020-07-08 15:49
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order(2);
System.out.println(order.orderId);
System.out.println(order.orderName);
}
}
class Order{
int orderId;
{
orderId = 1;
orderName = "order_BB";
}
String orderName = "order_AA";
public Order(int orderId){
this.orderId = orderId;
}
}
知识点6:关键字:final
/**
* final关键字的使用
*
* 1. final:最终的
*
* 2. final可以用来修饰:类、方法、变量
*
* 3. final修饰类:表示此类不能被继承。比如:String\StringBuffer\StringBuilder
*
* 4. final修饰方法:表示此方法不能被重写。比如:Object类中的getClass()
*
* 5.1 final修饰属性(或成员变量):此属性一旦赋值,就不能修改。--->常量
* 比如:Math中的PI
* >哪些位置可以给final修饰的属性赋值:显式初始化;代码块中赋值;构造器中赋值;
*
* >声明为static final的属性:全局常量
*
* 5.2 final修饰局部变量:常量。一旦赋值就不能修改。
* > 如果修饰形参的话,则在调用此方法时,给形参的常量赋值即可。
*
* @author shkstart
* @create 2020-07-08 16:26
*/
public class FinalTest {
final int MY_NUM1 = 0;
final int NUM2 ;
final int NUM3;
// final int NUM4;
{
NUM2 = 1;
}
public FinalTest(){
// NUM2 = 3;
NUM3 = 2;
}
public FinalTest(String info){
this();
}
// public void setNUM4(int num){
// this.NUM4 = num;
// }
//
// public static void main(String[] args) {
// FinalTest test = new FinalTest();
//
//
// test.setNUM4(10);
// }
public void method(){
final int num;
num = 1;
// num++;
System.out.println(num);
}
public void method1(final int num){
// num++;
}
}
//class MyString extends String{
//
//}
//final class A{
//
//}
//class B extends A{
//
//}
class C{
public void method(){
}
}
class D extends C{
// public void method(){
//
// }
}
- 说明:我们在开发时,主要考虑final修饰属性、形参时,需要的话,要及时加上final。
练习
包装类的练习
package com.atguigu.homework;
import java.util.Scanner;
import java.util.Vector;
/**
* 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
* 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。
* 创建Vector对象:Vector v=new Vector();
* 给向量添加元素:v.addElement(Object obj); //obj必须是对象
* 取出向量中的元素:Object obj=v.elementAt(0);
* 注意第一个元素的下标是0,返回值是Object类型的。
* 计算向量的长度:v.size();
* 若与最高分相差10分内:A等;20分内:B等;
* 30分内:C等;其它:D等
*
* @author shkstart
* @create 2020-07-08 9:37
*/
public class ScoreTest {
public static void main(String[] args) {
//1. 实例化Vector对象,用于存放学生成绩
Vector v = new Vector();
//2. 实例化Scanner对象,便于从键盘获取学生成绩
Scanner scanner = new Scanner(System.in);
//定义最高分的变量
int maxScore = 0;
//3. 根据提示,通过循环从键盘获取学生成绩,并保存在Vector中
for(;;){
System.out.print("请输入学生成绩:");
int score = scanner.nextInt();
//判断退出的条件
if(score < 0){
break;
}
// v.addElement(new Integer(score));//jdk5.0之前
v.addElement(score);//jdk5.0之后:自动装箱
//4. 获取学生的最高分
if(maxScore < score){
maxScore = score;
}
}
//5. 遍历学生成绩,获取各个学生的成绩和等级
for(int i = 0;i < v.size();i++){
int score = (int) v.elementAt(i);
char grade;
if(maxScore - score <= 10){
grade = 'A';
}else if (maxScore - score <= 20){
grade = 'B';
}else if(maxScore - score <= 30){
grade = 'C';
}else{
grade = 'D';
}
System.out.println("学生" + i + "成绩为:" + score + ",等级为:" + grade);
}
}
}
知识点7:单元测试方法
/**
* 单元测试方法的使用
*
* 1. 为什么使用单元测试方法:为了方便的在测试类中针对多个不同的代码或方法单独进行测试。
*
* 2. 如何实现?有什么要求?
* ① 单元测试方法声明前加上注解: @Test (来自于org.junit.Test)
* ② 单元测试方法是:public的、无返回值类型的、无形参的方法
* ③ 单元测试类是public的,提供空参的public权限的构造器
*
* 如果以上条件不满足,在执行单元测试方法时,报initializationError
*
* @author shkstart
* @create 2020-07-07 15:22
*/
public class JUnitTest { //单元测试类
@Test
public void test1(){ //单元测试方法
System.out.println("hello");
int m = 10;
int n = 20;
System.out.println( m + n);
}
@Test
public void test2(){
int m1 = 10;
int n1 = 10;
System.out.println(m1 == n1);//true
int m2 = 65;
char c1 = 'A';
System.out.println(m2 == c1);//true
float f1 = 65.0F;
System.out.println(m2 == f1);//true
}
@Test
public void testGet(){
int sum = get(10,20);
System.out.println(sum);
}
public int get(int m,int n){
return m + n;
}
}
补充知识:关于String字符串常量池的使用
public class StringTest {
public static void main(String[] args) {
//通过字面量的方式进行字符串的赋值操作。此时的字符串数据保存在字符串常量池中。
//字符串常量池中,不存在内容相同的字符串。
String s1 = "hello";//字面量赋值的方式
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1.equals(s2));//true
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
}
}
=====================================
知识点8:static关键字
static关键字的使用
*
* 1. static:静态的
* 2. 可以用来修饰:属性、方法、内部类、代码块
*
* 3. 使用static修饰属性:
*
* 3.1 回顾变量按照在类中声明的位置来分:
* 成员变量(属性):
* 类变量(或静态变量)
* 实例变量(或非静态变量)
* 局部变量:
* 方法内、构造器内、代码块内定义的
* 方法形参、构造器形参
* 3.2 非静态属性的特点:
* 每当我们创建一个类的实例,内存中就会在堆空间里分配一套类的非静态变量。类的多个实例的相同属性之间
* 没有任何关系。
* 3.3 静态属性的特点:
* ① 类的多个实例共享类的静态属性
* ② 类的静态属性在内存中就只有一份。存在于方法区的静态域中。
* ③ 类的静态属性随着类的加载而加载。
* (对比:类的非静态属性随着对象的创建而加载)
* ④ 静态属性 非静态属性
* 类 yes no
* 对象 yes yes
* ⑤ 当通过一个对象修改静态属性时,会导致其它对象对此静态属性的调用。
*
* 4. 使用static修饰方法:
* ① 随着类的加载而加载
* ② 静态方法 非静态方法
* 类 yes no
* 对象 yes yes
* ③ 静态方法内只能调用静态的属性、静态的方法。不能调用非静态的结构:属性、方法
* 非静态的方法内可以调用静态的结构或非静态的结构:属性、方法
*
*
* 5. 什么情况下适合将属性声明为static的?
* ① 当一个类的多个对象关于某一属性的值都是相同时,可以声明为static的。即:没有必要
* 给每个对象分配一份此属性的值时。
* ② 工具类中的属性通常都是静态的。
*
* 什么情况下适合将方法声明为static的?
* ① 通常操作静态属性的方法设置为静态的。(比如:get和set方法)
* ② 工具类中的方法通常都是静态方法
*
- 代码演示
public class StaticTest {
public static void main(String[] args) {
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 38;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "刘翔";
c2.age = 35;
c2.nation = "中国";
c1.info();
c2.info();
//使用"类.静态变量"的方式访问静态变量
System.out.println(Chinese.nation); //Math.PI
//不能使用"类.非静态变量"
// System.out.println(Chinese.name);
Chinese.show();//Math.sqrt(..),Math.random(),Math.round(..),Arrrys.sort(..)
}
}
class Chinese{
//非静态变量(或实例变量)
String name;
int age;
//静态变量(或类变量)
static String nation;
public void info(){
System.out.println("name = " + name + ", age = " + age + ", nation = " + nation);
show();
}
public static void show(){
System.out.println("我是中国人!!");
System.out.println("nation = " + nation);
//不能调用非静态的结构
// System.out.println("name = " + name);
// info();
}
}
- static的应用1
package com.atguigu.java1;
/**
* static的应用举例
* @author shkstart
* @create 2020-07-08 11:16
*/
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle(1.2);
System.out.println(c1);
Circle c2 = new Circle(2.2);
System.out.println(c2);
Circle c3 = new Circle();
System.out.println(c3);
System.out.println("创建的圆的个数为:" + Circle.getCircleInstanceCount());
}
}
class Circle{
private double radius;//半径
private int id;//编号
private static int init = 1001;
private static int circleInstanceCount;//记录创建的圆的个数
public Circle(double radius){
// this();
this.radius = radius;
this.id = init++;
circleInstanceCount++;
}
public Circle(){
this.id = init++;
circleInstanceCount++;
}
@Override
public String toString() {
return "Circle{" +
"radius=" + radius +
", id=" + id +
'}';
}
public int getId() {
return id;
}
public static int getCircleInstanceCount() {
return circleInstanceCount;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
}
- static的应用2
package com.atguigu.exer;
/**
* 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、
* “最小余额”,定义封装这些属性的方法。账号要自动生成。
* 编写主类,使用银行账户类,输入、输出3个储户的上述信息。
* 考虑:哪些属性可以设计成static属性。
* @author shkstart
* @create 2020-07-08 15:09
*/
public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account();
Account acct2 = new Account("qwerty",3000);
Account acct3 = new Account("asdfg",2000);
System.out.println(acct1);
System.out.println(acct2);
System.out.println(acct3);
}
}
class Account{
private int id ;//账号
private String password = "000000";//密码
private double balance;//存款余额
private static double interestRate;//存款利率
private static double minBalance;//最小余额
private static int init = 1000;//用于自动生成账号的属性
public Account(){
this.id = ++init;
}
public Account(String password,double balance){
this();
//this.id = ++init;
this.password = password;
this.balance = balance;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static double getInterestRate() {
return interestRate;
}
public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}
public static double getMinBalance() {
return minBalance;
}
public static void setMinBalance(double minBalance) {
Account.minBalance = minBalance;
}
public int getId() {
return id;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", password='" + password + '\'' +
", balance=" + balance +
'}';
}
}
知识点9:单例模式
- 设计模式
* 1.设计模式:是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模免去我们自己再思考和摸索。
* 就像是经典的棋谱,不同的棋局,我们用不同的棋谱。 ”套路”
*
* 经典的设计模式有23种
创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
对软件设计模式的研究造就了一本可能是面向对象设计方面最有影响的书籍:《设计模式》:《Design Patterns: Elements of Reusable Object-Oriented Software》(即后述《设计模式》一书),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。这几位作者常被称为"四人组(Gang of Four)",而这本书也就被称为"四人组(或 GoF)"书。
- 单例模式
2. 单例模式(单子模式,singleton):在整个的软件系统中,对某个类只能存在一个对象实例
*
* 3. 如何实现单例模式:
* 饿汉式、懒汉式
*
* 对比?
* 懒汉式好:延迟了对象的创建
* >有线程安全问题。
* 饿汉式好:没有线程的安全问题。
- 饿汉式
public class SingletonTest {
public static void main(String[] args) {
// Bank bank1 = new Bank();
// Bank bank1 = new Bank();
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);
}
}
//饿汉式
class Bank{
//1. 私有化类的构造器
private Bank(){
}
//2. 在类的内部创建对象
private static Bank bank = new Bank();
//3. 提供访问该对象的get方法
public static Bank getInstance(){
return bank;
}
}
- 懒汉式
/**
* 单例模式之懒汉式
*
* @author shkstart
* @create 2020-07-08 11:53
*/
public class SingletonTest1 {
public static void main(String[] args) {
Application app1 = Application.getInstance();
Application app2 = Application.getInstance();
System.out.println(app1 == app2);
}
}
class Application{
//1. 私有化类的构造器
private Application(){}
//2.声明当前类的实例
private static Application app = null;
//3. 调用方法时,根据app是否初始化,进行赋值。并返回
public static Application getInstance(){
if(app == null){
app = new Application();
}
return app;
}
}
知识点10:体会main()
/**
* main()的理解
* 1. 作为程序的入口
* 2. 可以看做是一个普通的静态方法
* 3. 除了使用Scanner之外,也可以使用main()从控制台传入需要的数据。都作为String
* 类型的变量接收。
* @author shkstart
* @create 2020-07-08 14:08
*/
public class MainDemo {
public static void main(String args[]) {
Main.main(new String[10]);
}
}
class Main{
public static void main(String[] args) {
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
- 如何在调用main()时,传参数
知识点11:代码块
* 类的成员之四:代码块的使用
*
* 1. 从格式上讲,命名为:代码块
* 从功能上讲,命名为:初始化块
*
* 2.代码块的分类:静态代码块 、 非静态代码块
*
* 3. 静态代码块:
* 1. 内部可以编写执行语句
* 2. 随着类的加载而执行
* 3. 静态代码块的执行要早于非静态代码块
* 4. 静态代码块只执行一次
* 5. 如果类中定义了多个静态代码块,则按照声明的先后顺序执行
* 6. 在内部可以调用当前类中的静态结构:属性、方法。不能调用非静态的结构
* 7. 作用:用来初始化当前类的静态属性。
*
*
* 4. 非静态代码块:
* 1. 内部可以编写执行语句
* 2. 随着对象的创建而执行
* 3. 每创建一个对象,非静态代码块就执行一次
* 4. 如果类中定义了多个非静态代码块,则按照声明的先后顺序执行
* 5. 在内部可以调用当前类中的静态结构和非静态结构:属性、方法
* 6. 作用:用来初始化创建的对象的实例变量。
- 代码演示
public class BlockTest {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println();
Person p2 = new Person();
System.out.println();
Person p3 = new Person();
}
}
class Person{
String name;
int age;
static String info = "我是人类";
public void eat(){
System.out.println("吃饭");
}
public static void show(){
System.out.println("我是一个勤劳的人类");
}
public Person(){
// System.out.println("Person()....");
}
//非静态代码块
{
System.out.println("我是非静态代码块1");
//可以调用类中静态的结构
System.out.println(info);
show();
//可以调用类中静态的结构
System.out.println(name);
eat();
}
{
System.out.println("我是非静态代码块2");
}
//静态代码块
static {
System.out.println("我是静态代码块1");
//可以调用类中静态的结构
System.out.println(info);
show();
//不可以调用类中静态的结构
// System.out.println(name);
// eat();
}
static {
System.out.println("我是静态代码块2");
}
}
- 练习
//由父及子,静态先行
class Root{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root(){
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid(){
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg){
//通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:"
+ msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf(){
//通过super调用父类中有一个字符串参数的构造器
super("尚硅谷");
System.out.println("Leaf的构造器");
}
}
public class LeafTest{
public static void main(String[] args){
new Leaf();
System.out.println();
new Leaf();
}
}
知识点12:属性赋值
/**
* 1. 有哪些位置可以给类中的属性赋值? (以非静态的属性说明)
* ① 默认初始化
* ② 显式初始化 / ⑤ 代码块中初始化
* ③ 构造器中初始化
*
* ④ 创建了对象以后,通过"对象.属性"或"对象.方法"的方式给属性赋值
*
*
* 2. 赋值的先后顺序?
* ① - ②、⑤ - ③ - ④
*
* 说明:② 、 ⑤ 的执行按照声明的位置决定的。先声明的先执行。
*
*
* @author shkstart
* @create 2020-07-08 15:49
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order(2);
System.out.println(order.orderId);
System.out.println(order.orderName);
}
}
class Order{
int orderId;
{
orderId = 1;
orderName = "order_BB";
}
String orderName = "order_AA";
public Order(int orderId){
this.orderId = orderId;
}
}
知识点13:final
/**
* final关键字的使用
*
* 1. final:最终的
*
* 2. final可以用来修饰:类、方法、变量
*
* 3. final修饰类:表示此类不能被继承。比如:String\StringBuffer\StringBuilder
*
* 4. final修饰方法:表示此方法不能被重写。比如:Object类中的getClass()
*
* 5.1 final修饰属性(或成员变量):此属性一旦赋值,就不能修改。--->常量
* 比如:Math中的PI
* >哪些位置可以给final修饰的属性赋值:显式初始化;代码块中赋值;构造器中赋值;
*
* >声明为static final的属性:全局常量
*
* 5.2 final修饰局部变量:常量。一旦赋值就不能修改。
* > 如果修饰形参的话,则在调用此方法时,给形参的常量赋值即可。
*
* @author shkstart
* @create 2020-07-08 16:26
*/
public class FinalTest {
final int MY_NUM1 = 0;
final int NUM2 ;
final int NUM3;
// final int NUM4;
{
NUM2 = 1;
}
public FinalTest(){
// NUM2 = 3;
NUM3 = 2;
}
public FinalTest(String info){
this();
}
// public void setNUM4(int num){
// this.NUM4 = num;
// }
//
// public static void main(String[] args) {
// FinalTest test = new FinalTest();
//
//
// test.setNUM4(10);
// }
public void method(){
final int num;
num = 1;
// num++;
System.out.println(num);
}
public void method1(final int num){
// num++;
}
}
//class MyString extends String{
//
//}
//final class A{
//
//}
//class B extends A{
//
//}
class C{
public void method(){
}
}
class D extends C{
// public void method(){
//
// }
}
- 说明:我们在开发时,主要考虑final修饰属性、形参时,需要的话,要及时加上final。
练习
包装类的练习
package com.atguigu.homework;
import java.util.Scanner;
import java.util.Vector;
/**
* 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
* 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。
* 创建Vector对象:Vector v=new Vector();
* 给向量添加元素:v.addElement(Object obj); //obj必须是对象
* 取出向量中的元素:Object obj=v.elementAt(0);
* 注意第一个元素的下标是0,返回值是Object类型的。
* 计算向量的长度:v.size();
* 若与最高分相差10分内:A等;20分内:B等;
* 30分内:C等;其它:D等
*
* @author shkstart
* @create 2020-07-08 9:37
*/
public class ScoreTest {
public static void main(String[] args) {
//1. 实例化Vector对象,用于存放学生成绩
Vector v = new Vector();
//2. 实例化Scanner对象,便于从键盘获取学生成绩
Scanner scanner = new Scanner(System.in);
//定义最高分的变量
int maxScore = 0;
//3. 根据提示,通过循环从键盘获取学生成绩,并保存在Vector中
for(;;){
System.out.print("请输入学生成绩:");
int score = scanner.nextInt();
//判断退出的条件
if(score < 0){
break;
}
// v.addElement(new Integer(score));//jdk5.0之前
v.addElement(score);//jdk5.0之后:自动装箱
//4. 获取学生的最高分
if(maxScore < score){
maxScore = score;
}
}
//5. 遍历学生成绩,获取各个学生的成绩和等级
for(int i = 0;i < v.size();i++){
int score = (int) v.elementAt(i);
char grade;
if(maxScore - score <= 10){
grade = 'A';
}else if (maxScore - score <= 20){
grade = 'B';
}else if(maxScore - score <= 30){
grade = 'C';
}else{
grade = 'D';
}
System.out.println("学生" + i + "成绩为:" + score + ",等级为:" + grade);
}
}
}
=====================================
知识点14:抽象类
- 理解抽象的设计思想
- abstract关键字的使用
/**
* 举例1:
* abstract class Account{
* double balance;
*
* //存钱、取钱的方法
* }
*
* class SavingAccount extends Account{
*
* }
* class CheckAccount extends Account{
*
* }
*
* class Customer{
* Account acct;
* public void setAccount(Account acct){ //Account acct = new SavingAccount();
* this.acct = acct;
* }
*
* }
*
* 1. abstract:抽象的
* 2. 可以用来修饰:类、方法
*
* 3. abstract 来修饰类:抽象类
* > 此类就不可以实例化(不能创建对象) ---> 凡是类,内部都有构造器。
* -->此时抽象类提供构造器的意义:为了子类对象实例化进行对抽象父类中构造器的调用
* > 在开发中,针对于抽象类,我们一定会提供其子类。在实现过程中,创建子类的对象。
*
* 4. abstract 来修饰方法:抽象方法
* > 特点:抽象方法,没有方法体结构。
* > 抽象类中可以没有抽象方法;但是,抽象方法所在的类,一定是抽象类。
* > 如果抽象类的子类重写了父类中的所有的抽象方法,则此子类可以实例化。
* 如果抽象类的子类没有重写父类中所有的抽象方法,则此子类也必须声明为abstract的。
*
*
*
* @author shkstart
* @create 2020-07-10 9:03
*/
- 代码举例
public class AbstractTest {
public static void main(String[] args) {
// Person p1 = new Person();
// p1.eat();
Student s1 = new Student();
s1.eat();
// Worker w1 = new Worker();
// w1.eat();
//提供抽象类的匿名子类的对象
Person p2 = new Person(){
@Override
public void eat() {
System.out.println("人:吃饭");
}
@Override
public void walk() {
System.out.println("人:走路");
}
@Override
public void breath() {
System.out.println("人:呼吸");
}
};
p2.eat();
//创建了BB的匿名子类的对象
BB b = new BB(){
};
}
}
abstract class BB{
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//抽象方法
public abstract void eat();
//抽象方法
public abstract void walk();
}
class Student extends Person{
String major;
public Student(){}
public Student(String name ,int age ,String major){
super(name, age);
this.major = major;
}
public void eat(){
System.out.println("学生:多吃有营养的食物");
}
public void walk(){
System.out.println("学生:背着书包上学");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的空气");
}
}
abstract class Worker extends Person{
String skill;
// public void eat(){
// System.out.println("工人:在工厂吃盒饭");
// }
// public void walk(){
// System.out.println("工人:在车间行走");
// }
}
- 举例
- abstract的补充说明
/**
* 不能用abstract修饰变量、代码块、构造器;
*
* 不能用abstract修饰私有方法、静态方法、final的方法、final的类。
*
* @author shkstart
* @create 2020-07-10 10:11
*/
public abstract class AbstractTest1 {
// private abstract void method();
//
// public static abstract void method1();
}
class A extends AbstractTest1{
}
- 练习1
public abstract class GeometricObject {
protected String color;//颜色
protected double weight;//权重
public GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//返回几何图形的面积
public abstract double findArea();
}
- 练习2
package com.atguigu.exer1;
/**
* @author shkstart
* @create 2020-07-10 14:28
*/
public abstract class Employee {//员工类
private String name;//姓名
private int id;//编号
private double salary;//薪水
public Employee(String name, int id, double salary) {//构造方法
this.name = name;
this.id = id;
this.salary = salary;
}
public abstract void work();//工作方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return
"name='" + name + '\'' +
", id=" + id +
", salary=" + salary;
}
}
package com.atguigu.exer1;
/**
* @author shkstart
* @create 2020-07-10 14:35
*/
public class CommonEmployee extends Employee{//普通员工类
public CommonEmployee(String name, int id, double salary) {//构造方法
super(name, id, salary);//调用父类的构造方法
}
@Override
public void work() {//工作方法
System.out.println("在工地搬砖");
}
@Override
public String toString() {
return "CommonEmployee{ " + super.toString() +"}";
}
}
package com.atguigu.exer1;
/**
* @author shkstart
* @create 2020-07-10 14:32
*/
public class Manager extends Employee {
private double bonus;//薪水
public Manager(String name, int id, double salary) {//构造方法
super(name, id, salary);//调用父类的构造方法
}
@Override
public void work() {//工作方法
System.out.println("在办公室工作");
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public String toString() {
return "Manager{" +
super.toString() +
",bonus=" + bonus +
"} ";
}
}
package com.atguigu.exer1;
/**
* @author shkstart
* @create 2020-07-10 14:35
*/
public class EmployeeTest {
public static void main(String[] args) {
Manager manager = new Manager("马大爷", 1001, 5000);
manager.setBonus(10000);
System.out.println(manager);
manager.work();
CommonEmployee commonEmployee = new CommonEmployee("杨鹏展", 1002, 500);
System.out.println(commonEmployee);
commonEmployee.work();
}
}
- 练习3
package com.atguigu.exer2;
/**
* 编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个Employee对象的
* 生日,则将该雇员的工资增加100元。
*
* 实验说明:
* (1)定义一个Employee类,该类包含:
* private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
* abstract方法earnings();
* toString()方法输出对象的name,number和birthday。
*
* @author shkstart
* @create 2020-07-10 14:41
*/
public abstract class Employee {
private String name;
private int number;
private MyDate birthday;
public Employee(String name, int number, MyDate birthday) {
this.name = name;
this.number = number;
this.birthday = birthday;
}
public Employee() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
//abstract方法earnings();
public abstract double earnings();
@Override
public String toString() {
return "name='" + name + '\'' +
", number=" + number +
", birthday=" + birthday.toDateString();
}
}
package com.atguigu.exer2;
/**
* (2)MyDate类包含:
* private成员变量year,month,day ;
* toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
*
* @author shkstart
* @create 2020-07-10 14:42
*/
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public MyDate() {
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public String toDateString(){
return year + "年" + month + "月" + day + "日";
}
}
package com.atguigu.exer2;
/**
* 定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处理。
* 该类包括:private成员变量monthlySalary;
* 实现父类的抽象方法earnings(),该方法返回monthlySalary值;
* toString()方法输出员工类型信息及员工的name,number,birthday。
*
*
* @author shkstart
* @create 2020-07-10 14:46
*/
public class SalariedEmployee extends Employee {
private double monthlySalary;//月工资
public SalariedEmployee(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
super(name, number, birthday);
this.monthlySalary = monthlySalary;
}
public SalariedEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public double getMonthlySalary() {
return monthlySalary;
}
public void setMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
@Override
public double earnings() {
return monthlySalary;
}
//toString()方法输出员工类型信息及员工的name,number,birthday
@Override
public String toString() {
return "SalariedEmployee{" + super.toString() + "}";
}
}
package com.atguigu.exer2;
/**
* (4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理。
* 该类包括:
* private成员变量wage和hour;
* 实现父类的抽象方法earnings(),该方法返回wage*hour值;
* toString()方法输出员工类型信息及员工的name,number,birthday。
*
*
* @author shkstart
* @create 2020-07-10 14:50
*/
public class HourlyEmployee extends Employee {
private int hour;//小时数
private int wage;//单位小时的工资
@Override
public double earnings() {
return hour * wage;
}
public HourlyEmployee() {
}
public HourlyEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public HourlyEmployee(String name, int number, MyDate birthday, int hour, int wage) {
super(name, number, birthday);
this.hour = hour;
this.wage = wage;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getWage() {
return wage;
}
public void setWage(int wage) {
this.wage = wage;
}
//toString()方法输出员工类型信息及员工的name,number,birthday。
@Override
public String toString() {
return "HourlyEmployee{" + super.toString() + "}";
}
}
package com.atguigu.exer2;
import java.util.Scanner;
/**
* 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
* 利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象生日。
* 当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。
*
* @author shkstart
* @create 2020-07-10 14:55
*/
public class PayrollSystem {
public static void main(String[] args) {
Employee[] emps = new Employee[2];
emps[0] = new SalariedEmployee("杨超宇",1001,new MyDate(1994,4,02),20000);
emps[1] = new HourlyEmployee("闫宏浩",1002,new MyDate(1988,7,10),240,100);
Scanner scanner = new Scanner(System.in);
System.out.println("请输入当前的月份:");
int month = scanner.nextInt();
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
double monthlyMoney = emps[i].earnings();
if(month == emps[i].getBirthday().getMonth()){
monthlyMoney += 200;
}
System.out.println("月工资为:" + monthlyMoney);
}
}
}
知识点15:接口
- 基本使用
/**
* interface关键字的使用
* 1. 我们使用interface来声明一个接口。
* 接口与类,是Java中并列关系的两个结构。
*
* 2. 接口,可以理解为特定功能的封装。通过类实现接口的方法,进而体现功能的扩充。同时,还不
* 影响此类单继承父类的情况。
* 而且,一个类可以实现多个接口。
* 3. 格式:class SubClass extends SuperClass implements 接口1,接口2,...
*
* 4. 关于接口的使用:
* JDK 7及之前:只能定义全局常量 和 抽象方法
* > 全局常量使用:public static final 修饰。也可以省略不写
* > 抽象方法使用:public abstract 修饰。也可以省略不写
*
* JDK 8: 增加了对静态方法、默认方法的定义。
* JDK 9: 增加了对私有方法的定义。
*
* 5. 实现类在实现了接口之后,必须要实现接口中的所有抽象方法,方可实例化。
* 否则,实现类如果没有实现接口中的所有抽象方法,则此实现类仍为抽象类。
*
* 6. 接口中不能定义构造器的。也就是说,接口不能实例化。
*
* 7. 类与接口之间是实现关系,而且是可以多实现的。
* 接口与接口之间是继承关系,而且是可以多继承的。
*
*
* 补充说明:
* 类继承类的关系:is - a
* 类实现接口的关系: like - a
* 类及其属性的关系: has - a
*
* @author shkstart
* @create 2020-07-10 10:30
*/
- 代码演示
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
// Flyable.MAX_SPEED = 8000;
}
}
interface Flyable{
//全局常量
public static final int MIN_SPEED = 1;
int MAX_SPEED = 7900;
//抽象方法
public abstract void fly();
void stop();
}
interface AttackAble{
void attack();//攻击
}
abstract class Plane implements Flyable{
@Override
public void fly() {
}
// @Override
// public void stop() {
//
// }
}
class Bullet implements Flyable,AttackAble{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
}
interface AA{
}
interface CC{
}
interface DD extends AA,CC{
}
- 体会接口作为标准、规范的存在
/**
* 1. 接口的本质是契约,标准,规范
*
* 2. 接口的使用:实现了多态性。
*
* 3. 匿名实现类的理解
*
* @author shkstart
* @create 2020-07-10 11:24
*/
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的实现类的对象printer
Printer printer = new Printer();
com.transferData(printer);
//2.创建了接口的实现类的匿名对象
com.transferData(new Flash());
//3. 创建接口的匿名实现类的对象
USB camera = new USB(){
@Override
public void start() {
System.out.println("照相机开始工作");
}
@Override
public void stop() {
System.out.println("照相机结束工作");
}
};
com.transferData(camera);
//4. 创建接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){ //体现了多态性。
usb.start(); //虚方法调用
System.out.println("========具体的数据传输细节=======");
usb.stop();
}
}
interface USB{
void start();
void stop();
}
class Printer implements USB{ //打印机
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
class Flash implements USB{//U盘
@Override
public void start() {
System.out.println("U盘开始工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
- java8中接口的新特性
package com.atguigu.java2;
import java.net.SocketTimeoutException;
/**
* @author shkstart
* @create 2020-07-10 15:37
*/
public interface CompareA {
public static void method1() {
System.out.println("CompareA:北京");
}
public default void method2() {
System.out.println("CompareA:上海");
}
default void method3() {
System.out.println("CompareA:广州");
}
public default void method4(){
System.out.println("CompareA:深圳");
}
}
package com.atguigu.java2;
/**
* @author shkstart
* @create 2020-07-10 15:50
*/
public interface CompareB {
public default void method2() {
System.out.println("CompareB:上海");
}
}
package com.atguigu.java2;
/**
* @author shkstart
* @create 2020-07-10 15:46
*/
public class SuperClass {
public void method4(){
System.out.println("SuperClass:深圳");
}
}
package com.atguigu.java2;
/**
* @author shkstart
* @create 2020-07-10 15:39
*/
public class SubClass extends SuperClass implements CompareA,CompareB {
public void method3() {
System.out.println("SubClass:广州");
}
public void method4(){
System.out.println("SubClass:深圳");
}
public void method2() {
System.out.println("SubClass:上海");
}
public void method(){
//6. 如何在子类(或实现类)中调用父类或接口中被重写的方法
//调用父类的方法:
super.method4();
//调用接口中的方法:
CompareA.super.method2();
CompareB.super.method2();
}
}
package com.atguigu.java2;
/**
* @author shkstart
* @create 2020-07-10 15:40
*/
public class SubClassTest {
public static void main(String[] args) {
//1. 接口中静态方法的调用:只能使用接口本身来调用,其实现类不可以调用。
CompareA.method1();
// SubClass.method1();
//2. 可以通过实现类的对象,调用接口中的默认方法
SubClass sub1 = new SubClass();
sub1.method2();
//3.实现类可以重写接口中的默认方法。
sub1.method3();
//4.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,则子类在没有
//重写此方法的情况下,默认调动的是父类中声明的方法。--->类优先原则
//补充:如果子类(或实现类)重写了上述的方法,则调用的就是自己重写的方法。
sub1.method4();
//5.如果实现类实现了多个接口,且多个接口中声明了同名同参数的方法。则
//子类必须重写此方法。否则,编译不通过。 --->接口冲突。
sub1.method2();
//6. 见SubClass内
sub1.method();
}
}
知识点16:内部类
- 基本知识点
/**
* 类的成员之五:内部类
*
* 1. 分类:
* 成员内部类:直接声明在外部类的内部。
*
* 局部内部类:声明在方法内、代码块内等的内部类。
*
* 2. 关于成员内部类的使用:
* 2.1 作为外部类的一个成员:
* > 可以使用4种不同的权限进行修饰
* > 可以使用static进行修饰
* > 可以在内部类中调用外部类的成员
*
* 2.2 作为类的:
* > 可以在内部声明属性、方法、构造器、代码块、内部类....
* > 可以被abstract、final修饰。
*
*
*
* 3. 学习内部类需要掌握的三个知识点
* ① 如何创建成员内部类的对象
* ② 如何在成员内部类中调用外部类的属性、方法
* ③ 熟悉局部内部类的基本使用: 见 InnerClassTest1.java
*
* @author shkstart
* @create 2020-07-10 16:19
*/
-
代码举例
-
外部类的使用
public class InnerClassTest { public static void main(String[] args) { //创建静态的成员内部类 Person.Bird bird = new Person.Bird(); //创建非静态的成员内部类 Person p = new Person(); Person.Dog dog = p.new Dog(); dog.info(); dog.show("旺财"); } } class Person{ String name = "小明"; int age = 1; //静态的成员内部类 static class Bird{ } //非静态的成员内部类 class Dog{ String name = "小花"; public void info(){ //直接调用外部类的属性和方法 System.out.println(age); Person.this.eat(); } public void show(String name){ System.out.println(name); System.out.println(this.name); System.out.println(Person.this.name); } public void eat(){ System.out.println("狗吃骨头"); } } public void eat(){ System.out.println("人吃饭"); } }
-
内部类的使用
package com.atguigu.java3; /** * 体会局部内部类的使用 * * @author shkstart * @create 2020-07-10 16:40 */ public class InnerClassTest1 { //此种方式使用局部内部类:不常见 public void method(){ //声明一个局部内部类 class A{ } } //常见如下的操作: public Comparable getComparable(){ //方式一: /*//内部声明一个接口的实现类 class MyComparable implements Comparable{ @Override public int compareTo(Object o) { return 0; } } return new MyComparable();*/ //方式二:创建了接口的匿名实现类的匿名对象 return new Comparable(){ @Override public int compareTo(Object o) { return 0; } }; } }
-