目录
1.1static 修饰的属性,相较于实例变量,有哪些特别之处(>=3点)
5.4abstract 能修饰哪些结构? 修饰以后,有什么特点?
2.1编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个
2.2.声明抽象类,并包含抽象方法。测试类中创建一个继承抽象类的匿名子类的对象
一、概念
1.关键字static(静态的)
1.1static 修饰的属性,相较于实例变量,有哪些特别之处(>=3点)
①随着类的加载而加载,可以通过"类.静态变量"的方式进行调用;
②早于对象的创建;
③只要权限允许,可以通过”对象.static属性”的方式进行调用;
④由于类只会加载一次,则静态变量在内存中也只会存在一份,存在于方法区的静态域
1.2static修饰的静态方法为什么不能被重写
静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写。
但非静态方法是在对象实例化时才单独申请内存空间,为每一个实例分配独立的运行内存,因而可以重写。
2.final关键字
2.1.排错:
public class Something {public int addOne( final int x ) {return ++ x ;// return x + 1;}}错误:return ++x;原因:形参x被关键字final修饰,方法体内不能修改参数值++x-->x = x+1;x的值发生了改变。return x+1;正确-->x值没有改变
public class Something {public static void main(String[] args ) {Other o = new Other();new Something().addOne( o );}public void addOne( final Other o ) {// o = new Other();o . i ++;}}class Other {public int i ;}错误: o = new Other();原因:在方法中使用final 修饰Other类的实例o,那么实例o只能new一个对象,在方法体中不能再new Other();o . i ++;正确 -->实例o并没有在创建一个新的对象,o.i++,改变的是对象的属性
2.2 final 可以用来修饰哪些结构,分别表示什么意思
final可以用来修饰的结构:类、方法、变量
final 用来修饰一个类:此类不能被其它类所继承。
final 用来修饰方法:表明此方法不可以被重写
final 用来修饰变量,此时的“变量”被称为一个常量
3.单例设计模式
静态方法的使用
3. 1代码实现单例模式的饿汉式
//饿汉式
class Bank{
//1.私有化类的构造器
private Bank() {
}
//2.内部常见类的对象
//4.要求此对象也必须声名为静态的
private static Bank instance = new Bank();
//3.提供公共的静态方法,返回类的对象
public static Bank getInstance() {
return instance;
}
}
3.2. 代码实现单例模式的懒汉式
单例模式的懒汉式 -目前还是线程不安全的。
class Order{
//1.私有化类的构造器
private Order() {
}
//2.声明当前类对象,没有初始化
//4.此对象也必须声名为static的
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public static Order getInstance() {
if(instance == null) {
instance = new Order();
}
return instance;
}
}
4.类的属性赋值的位置有哪些?先后顺序为何?
①默认初始化
②显式初始化 、③代码块中初始化:二者,谁先声明先执行;
④构造器中初始化
⑤通过”对象.属性” 或”对象.方法”的方式赋值
执行的先后顺序:① - ②/③ - ④ - ⑤
5.Abstract关键字(抽象的)
5.1为什么抽象类不可以使用final关键字声明?
final修饰的方法不能被重写,final修饰的类不能被继承
5.2一个抽象类中可以定义构造器吗?
可以定义构造器
原因:子类继承父类的属性、方法需要通过构造器来进行
抽象与继承不相矛盾
5.3是否可以这样理解:抽象类就是比普通类多定义了抽象方
法,除了不能直接进行类的实例化操作之外,并没有任何的不同?
不能这样理解
原因:
抽象类中一般情况下有抽象方法,但也可以没有抽象方法;
但有抽象方法的类一定是抽象类
5.4abstract 能修饰哪些结构? 修饰以后,有什么特点?
abstract可以修饰类、方法
特点:
abstract修饰类:抽象类
> 此类不能实例化
> 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化化的全过程)
> 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作。
abstract修饰方法:抽象方法
>抽象方法只有方法的声明,没有方法体
>包含抽象方法的类一定是一个抽象类。反之,抽象类中可以没有抽象方法。
>若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
6.接口(interface)
6.1排错
①interface A {int x = 0;}class B {int x = 1;}class C extends B implements A {public void pX() {System. out .println(x);}public static void main(String[] args ) {new C().pX();}}-----------------------------------------------------------------------------------------------------------------------错误代码:System. out .println(x);原因:The field x is ambiguous:字段x不明确;接口、父类中都有x,不明确;修改:接口和父类的优先权限相同。System.out.println(super.x);//父类中的x,super关键字调用父类的信息
System.out.println(A.x);//接口中的x ,接口中属性是静态常量,静态属性可以使用类名.属性的方式调用拓展:如果将接口A,需改为class A,class B extends A,System.out.println(x);x是多少?为什么?答: x=1;原因:class B是 class C的直接父类,class C 首先会从直接父类中查找属性x,找到后就直接调用,如果在直接父类中没有找到对应的属性,会向间接父类中寻找,直接父类优先级高于间接父类; 直接父类优先于间接父类注: 子类继承父类,方法可以重写,属性不能重写。
②interface Playable {void play();}interface Bounceable {void play();}interface Rollable extends Playable, Bounceable {Ball ball = new Ball( "PingPang" );}class Ball implements Rollable {private String name ;public String getName() {return name ;}public Ball(String name ) {this . name = name ;}public void play() {ball = new Ball( "Football" );System. out .println(ball.getName());}}-----------------------------------------------------------------------------------------------------------错误代码:ball = new Ball( "Football" );错误原因:ball在接口中已经定义了,在接口中可以定义全局常量和抽象方法,所以ball是 一个常量,常量值不能改变
6.2判断对错,接口、抽象类
接口是否能继承接口?---->能继承 extends
抽象类是否能实现(implements)接口? 能实现 implements
抽象类是否能继承非抽象的类? 能继承 extends
7.抽象类和接口有哪些共同点和区别?
相同点:
抽象类和接口都不能实例化,都可以被继承。
不同点:
抽象类可以声明构造器,接口不能声明构造器。
抽象类是单继承,接口是多继承
>抽象类被继承时一个子类只能继承一个抽象类,接口可以一次性继承多个。
定义方式不一样,实现方式不一样
>抽象类abstract 继承extends
>接口interface 实现implements抽象类中可以有非抽象方法,接口中只能定义抽象方法(JDK7版本之前)。
>JDK8 接口更像是一个抽象类
接口更像是一个模板。
8.内部类
如何创建静态成员内部类和非静态成员内部类的对象?
//创建Dog实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类)
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
二、编程
1.关键字static
1.1编写一个类实现银行账户的概念
package com.atguigu.exer;
public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account();
Account acct2 = new Account("qwerty", 2000);
Account acct3 = new Account("qulinge", 2000);
System.out.println("acct1的id:"+acct1.getId());
System.out.println("acct1的id:"+acct2.getId());
System.out.println("acct1的id:"+acct3.getId());
System.out.println(acct1);
System.out.println(acct2);
System.out.println(acct3);
Account.setInterestRate(0.012);
Account.setMinMoney(100);
System.out.println("利率:"+Account.getInterestRate()*100+"%");
System.out.println("最小余额:"+Account.getMinMoney());
}
}
----------------------------------------------------------------------------------------
package com.atguigu.exer;
/*
* 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,
* 定义封装这些属性的方法。
* 账号要自动生成。
* 编写主类,使用银行账户类,输入、输出3个储户的上述信息。考虑:哪些属性可以设计成static属性。
*/
public class Account {
private int id ;//账户
private String pwd = "000000000";//密码
private double balance;//余额
private static double interestRate;//利率
private static double minMoney = 1.0;//最小余额
private static int init = 1001;//用于自动生成id使用
public Account() {
id = init++;
}
public Account(String pwd,double balance) {
id = init++;
this.pwd = pwd;
this.balance = balance;
}
public int getId() {
return this.id;
}
public String getPwd() {
return this.pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public double getBalance() {
return balance;
}
public static double getInterestRate() {
return interestRate;
}
public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}
public static double getMinMoney() {
return minMoney;
}
public static void setMinMoney(double minMoney) {
Account.minMoney = minMoney;
}
@Override
public String toString() {
return "Account [id=" + id + ", pwd=" + pwd + ", balance=" + balance + "]";
}
}
2、抽象类和抽象方法
2.1编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个
Employee对象的生日,则将该雇员的工资增加100元。
实验说明:( 1 )定义一个 Employee 类,该类包含:private 成员变量 name,number,birthday ,其中 birthday 为 MyDate 类的对象;abstract 方法 earnings() ;toString() 方法输出对象的 name,number 和 birthday 。(2) MyDate 类包含 :private 成员变量 year,month,day ;toDateString() 方法返回日期对应的字符串: xxxx 年 xx 月 xx 日(3)定义 SalariedEmployee 类继承 Employee 类,实现按月计算工资的员工处理。该类包括: private 成员变量 monthlySalary ;实现父类的抽象方法 earnings(), 该方法返回 monthlySalary 值; toString() 方法输出员工类型信息及员工的 name , number,birthday 。(4)参照 SalariedEmployee 类定义 HourlyEmployee 类,实现按小时计算工资的员工处理。该类包括:private 成员变量 wage 和 hour ;实现父类的抽象方法 earnings(), 该方法返回 wage*hour 值;toString() 方法输出员工类型信息及员工的 name , number,birthday 。(5)定义 PayrollSystem 类,创建 Employee 变量数组并初始化,该数组存放各类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类型 ,name,number,birthday, 以及该对象生日。当键盘输入本月月份值时,如果本月是某个 Employee 对象的生日,还要输出增加工资信息。提示:// 定义 People 类型的数组 People c1[]=new People[10];// 数组元素赋值c1[0]=new People("John","0001",20);c1[1]=new People("Bob","0002",19);// 若 People 有两个子类 Student 和 Officer ,则数组元素赋值时,可以使父类类型的数组元素指向子类。c1[0]=new Student("John","0001",20,85.0);c1[1]=new Officer("Bob","0002",19,90.5);
package com.atguigu.exer2;
/*
* (1)定义一个Employee类,
* 该类包含:private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
* abstract方法earnings();
* toString()方法输出对象的name,number和birthday。
*/
public abstract class Employee {
//属性
private String name;
private int number;//员工号
private MyDate birthday;
public Employee() {
}
public Employee(String name,int number,MyDate birthday) {
this.name = name;
this.number = number;
this.birthday = birthday;
}
public String getName() {
return name;
}
public double getNumber() {
return number;
}
public MyDate getBirthday() {
return birthday;
}
public void setName(String name) {
this.name = name;
}
public void setNumber(int number) {
this.number = number;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
public abstract double earnings();//薪水
@Override
public String toString() {
return "Employee [name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString() + "]";
}
}
package com.atguigu.exer2;
/*
* MyDate类包含:
* private成员变量year,month,day ;
* toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
*/
public class MyDate {
private int year;
private int month;
private int day;
public MyDate() {
}
public MyDate(int year,int month,int day) {
this.year = year;
this.month = month;
this.day = day;
}
public String toDateString() {
return year+"年"+month+"月"+day+"日";
}
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;
}
}
package com.atguigu.exer2;
/*
* 定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处理。
* 该类包括:private成员变量monthlySalary;
* 实现父类的抽象方法earnings(),该方法返回monthlySalary值;
* toString()方法输出员工类型信息及员工的name,number,birthday。
*
*/
public class SalariedEmployee extends Employee{
private double monthlySalary;//月工资
public SalariedEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
super(name, number, birthday);
this.monthlySalary = monthlySalary;
}
public double getMonthlySalary() {
return monthlySalary;
}
public void setMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
@Override
//薪资
public double earnings() {
return monthlySalary;
}
public String toString() {
return "SalariedEmployee ["+super.toString() + "]";
}
}
package com.atguigu.exer2;
public class HourlyEmployee extends Employee{
private double wage;//每小时的工资
private double hour;//月工作的小时数
public HourlyEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public HourlyEmployee(String name, int number, MyDate birthday, double wage, double hour) {
super(name, number, birthday);
this.wage = wage;
this.hour = hour;
}
@Override
public double earnings() {
return wage*hour;
}
@Override
public String toString() {
return "HourlyEmployee [" +super.toString()+ "]";
}
public double getWage() {
return wage;
}
public void setWage(double wage) {
this.wage = wage;
}
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
}
package com.atguigu.exer2;
import java.util.Calendar;
import java.util.Scanner;
/*
* 定义PayrollSystem类,
* 创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
* 利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象生日。
* 当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。
*
*
*/
public class PayrollSystem {
public static void main(String[] args) {
//方式一:
// Scanner scan = new Scanner(System.in);
// System.out.print("本月月份:");
// int month = scan.nextInt();
//方式二:
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH);//获取当前月份
System.out.println(month);
Employee[] emps = new Employee[2];
emps[0] = new SalariedEmployee("李白", 001, new MyDate(1998, 12, 20),10000);
emps[1] = new HourlyEmployee("杜甫", 002, new MyDate(2000, 1, 1),60,240);
for(int i=0;i < emps.length;i++) {
System.out.println(emps[i]);
//emps[i].getBirthday().getMonth():生日月份
double salary = emps[i].earnings();
System.out.println(" 月工资是"+salary);
if((month+1) == emps[i].getBirthday().getMonth()) {
System.out.println(emps[i].getName()+"生日快乐!奖励100元");
}
}
}
// public void func(Employee employee) {
// if(employee instanceof SalariedEmployee) {
// SalariedEmployee s = (SalariedEmployee)employee;
// double salary = s.getMonthlySalary()+100;
// s.setMonthlySalary(salary);
//
// }
// if(employee instanceof HourlyEmployee) {
// HourlyEmployee h = (HourlyEmployee)employee;
//
// }
//
// }
}
2.2.声明抽象类,并包含抽象方法。测试类中创建一个继承抽象类的匿名子类的对象
package com.atguigu.exer3;
public class Test15 {
public static void main(String[] args) {
//抽象类不能实例化对象
//非匿名子类,非匿名对象
BB b = new BB();
b.m();
//非匿名子类,匿名对象
new BB().m();
//抽象类的匿名子类,非匿名对象
AA a = new AA() {
@Override
public void m() {
System.out.println("抽象类的匿名子类,非匿名对象");
}
};
a.m();
//抽象类的匿名子类,匿名对象
new AA() {
public void m() {
System.out.println("抽象类的匿名子类,匿名对象");
}
}.m();;
}
}
abstract class AA{
public abstract void m();
}
class BB extends AA{
@Override
public void m() {
System.out.println("这是一个抽象类的子类");
}
}
3.接口(interface)
3.1定义一个接口用来实现两个对象的比较。
>定义一个接口用来实现两个对象的比较。>interface CompareObject{public int compareTo(Object o); //若返回值是 0 , 代表相等 ; 若为正数,代表当前对象大;负数代表当前对象小}>定义一个 Circle 类,声明 redius 属性,提供 getter 和 setter 方法>定义一个 ComparableCircle 类,继承 Circle 类并且实现 CompareObject 接口。在ComparableCircle 类中给出接口中方法 compareTo 的实现体,用来比较两个圆的半径大小。>定义一个测试类 InterfaceTest ,创建两个 ComparableCircle 对象,调用 compareTo方法比较两个类的半径大小。>思 考 : 参 照 上 述 做 法 定 义 矩 形 类 Rectangle 和 ComparableRectangle 类 , 在 ComparableRectangle类中给出 compareTo 方法的实现,比较两个矩形的面积大小。
package com.atguigu.exer3;
/*
* 定义一个Circle类,声明redius属性,提供getter和setter方法
*/
public class Circle {
// private double redius;
//
// public Circle() {
// super();
// }
//
// public Circle(double redius) {
// super();
// this.redius = redius;
// }
//
// public double getRedius() {
// return redius;
// }
// public void setRedius(double redius) {
// this.redius = redius;
// }
//使用包装类来定义
private Double radius;
public Double getRadius() {
return radius;
}
public void setRadius(Double radius) {
this.radius = radius;
}
public Circle() {
}
public Circle(Double radius) {
super();
this.radius = radius;
}
}
package com.atguigu.exer3;
/*
* interface CompareObject{
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
public int compareTo(Object o);
}
*
*/
public interface CompareObject {
public int compareTo(Object o);
}
package com.atguigu.exer3;
/*
* 定义一个ComparableCircle类,
* 继承Circle类并且实现CompareObject接口。
* 在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
*/
public class ComparableCircle extends Circle implements CompareObject{
public ComparableCircle(Double redius) {
super(redius);
}
@Override
public int compareTo(Object o) {
if(this == o) {
return 0;
}
if(o instanceof ComparableCircle) {
ComparableCircle c = (ComparableCircle)o;
//错误的,原因:强转时损失精度,如果3.6-3.4=0.2,int型下会是0
// return (int)(this.getRedius() - c.getRedius());
//正确的
//第一种
// double index = this.getRedius() - c.getRedius();
// if(index > 0) {
// return 1;
// }else if(index == 0) {
// return 0;
// }else {
// return -1;
// }
//第二种方法:使用包装类
//当属性声明为Double类型时,可以调用包装类的方法
return this.getRadius().compareTo(c.getRadius());
}else {
//return 0;
throw new RuntimeException("传入数据不匹配");
}
}
}
package com.atguigu.exer3;
import javax.sound.midi.Soundbank;
/*
* 定义一个测试类InterfaceTest,
* 创建两个ComparableCircle对象,
* 调用compareTo方法比较两个类的半径大小。
*/
public class ComparableCircleTest {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(3.4);
ComparableCircle c2 = new ComparableCircle(3.6);
int compareValue = c1.compareTo(c2);
if(compareValue > 0) {
System.out.println("C1对象大");
}else if(compareValue < 0) {
System.out.println("c2对象大");
}else {
System.out.println("c1与才一样大");
}
//输入异常
int compareValue1 = c1.compareTo(new String("AA"));
System.out.println(compareValue1);
}
}
4.内部类
创建静态成员内部类和非静态成员内部类
class Person{
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类)
// Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println();
bird.dispaly("黄鹂");
}
}
class Person{
String name = "小明";
int age;
public void eat() {
System.out.println("人,吃饭");
}
//成员内部类
//静态成员内部类
static class Dog{
String name;
int age;
public void show() {
System.out.println("卡拉是条狗");
// eat();//静态不能调非静态
}
}
//非静态成员内部类
final class Bird{
String name = "杜鹃";
public Bird() {
}
public void sing() {
System.out.println("我是一只小小鸟");
eat();//省略了Person.this.
//Person.this.eat();//调用外部类的非静态属性
//若是内部类与外部类没有重名,可直接调用属性、方法
System.out.println(age);
}
public void dispaly(String name) {
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
}