Java基础之面向对象(下)
目录
4.多态的应用:模板方法设计模式(TemplateMethod)
一、关键字:static
1.static的引入
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上 的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象, 其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少 对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个 国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中 都单独分配一个用于代表国家名称的变量。
如果想让一个类的所有实例共享数据,就用类变量!
2.类属性、类方法的设计思想
类属性作为该类各个对象之间共享的变量。在设计类时,分析哪 些属性不因对象的不同而改变,将这些属性设置为类属性。相应 的方法设置为类方法。
如果方法与调用者无关,则这样的方法通常被声明为类方法,由 于不需要创建对象就可以调用类方法,从而简化了方法的调用。
3.static的使用范围和特点
使用范围:
在Java类中,可用static修饰属性、方法、代码块、内部类
被修饰后的成员具备以下特点:
随着类的加载而加载
优先于对象存在
修饰的成员,被所有对象所共享
访问权限允许时,可不创建对象,直接被类调用
4.类变量 vs 实例变量内存解析
5.代码演示
package com.tyl.java;
import java.util.Enumeration;
import java.util.jar.Attributes.Name;
import javax.sound.midi.MidiDevice.Info;
/*
* static关键字的使用
1.static:静态的
2,static可以用来修饰:属性、方法、代码块、内部类
*
* 3.使用static修饰属性:静态变量(或者 类变量)
* 3.1 属性,按是否使用static修饰,又分为:静态属性Vs非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的
非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致
其他对象调用此静态变量时,是修改过了的。
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。可以通过“类。静态变量"的方式进行调用
② 静态变量的加载要早于对象的创建
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中
④
类变量 实例变量
类 yes no
对象 yes yes
3.3 静态属性举例:System.out; Math.PI;
4.使用static修饰方法:静态方法
①、随着类的加载而加载,可以通过"类,静态方法"的方式进行调用
⑤、 静态方法 非静态方法
类 yes no
对象 yes yes
③、静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
5.static注意点:
5.1在静态的方法内,不能使用this关键字、super关键字
5,2关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
6. 开发中,如何确定一个属性是否要声明为static的?
> 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
> 类中的常量也常常声明为static
开发中,如何确定一个方法是否要声明为static的?
>操作静态属性的方法,通常设置为static的
>工具类中的方法,习惯上声明为static的。比如:Math、Arrays、Collections
*
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "chain";
Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 30;
c2.nation = "chain123";
System.out.println(c1.nation); // chain123
c1.eat();
Chinese.show();
}
}
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("chichichi");
//调用非静态结构
this.info();
System.out.println("name; " + name);
//调用静态结构
walk();
System.out.println("nation : " + Chinese.nation);
}
public static void show(){
System.out.println("wshizhongupren");
不能调用非静态的结构
// eat();
// name = "tom";
//可以调用静态的结构
System.out.println(Chinese.nation);
walk();
}
public static void walk(){
}
public void info(){
System.out.println("name: "+ name + ",age: " + age);
}
}
6.练习1
package com.tyl.java;
/*
* static的练习
*
*/
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle(3.4);
System.out.println("c1的id:" + c1.getId());
System.out.println("c2的id:" + c2.getId());
System.out.println("c3的id:" + c3.getId());
System.out.println("total为:" + Circle.getTotal());
}
}
class Circle{
private double radius;
private int id; //自动赋值
public Circle(){
id = init++;
total++;
}
public Circle(double radius){
this();
// id = init++;
// total++;
this.radius = radius;
}
private static int total;
private static int init = 1001; //static声明的属性被所有对象所共享
public double findArea(){
return 3.14*radius*radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public int getId() {
return id;
}
public static int getTotal() {
return total;
}
}
7.练习2
Account类
package com.tyl2.java;
/*
*
* 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些
属性的方法。账号要自动生成。编写主类,使用银行账户类,输入、输出3个储户的上述信息。
考虑:哪些属性可以设计成static属性。
*/
public class Acccount {
private int id;
private String pwd = "000000";
private double balance;
private static double interestRate;
private static double minMoney = 1.0;
private static int init = 1001; // 用于自动生成id使用的
public Acccount(){
id = init++;
}
public Acccount(String pwd, double balance){
id = init++;
this.pwd = pwd;
this.balance = balance;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public static double getInterestRate() {
return interestRate;
}
public static void setInterestRate(double interestRate) {
Acccount.interestRate = interestRate;
}
public static double getMinMoney() {
return minMoney;
}
public static void setMinMoney(double minMoney) {
Acccount.minMoney = minMoney;
}
public int getId() {
return id;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Acccount [id=" + id + ", pwd=" + pwd + ", balance=" + balance + "]";
}
}
test测试类
package com.tyl2.java;
/*
*/
public class AccountTest {
public static void main(String[] args) {
Acccount acct1 = new Acccount();
Acccount acct2 = new Acccount("123456", 5000);
System.out.println(acct1);
System.out.println(acct2);
Acccount.setInterestRate(0.012);
Acccount.setMinMoney(100);
System.out.println(acct1.getInterestRate());
System.out.println(acct1.getMinMoney());
}
}
8.单例 (Singleton)设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典 的棋谱,不同的棋局,我们用不同的棋谱。”套路”
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
常用设计模式--23种经典的设计模式:
创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模
式、中介者模式、解释器模式。
1.饿汉式
package com.tyl2.java;
/*
* 单例设计模式:
1、所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
2、如何实现?饿汉式 vs 懒汉式
3.区分饿汉式和懒汉式
饿汉式:
坏处:对象加载时间过长。
好处:饿汉式是线程安全的
懒汉式:好处:延迟对象的创建
目前的写法坏处:线程不安全。~~~>到多线程内容时,再修改
*
*/
public class SingletonTest1 {
public static void main(String[] args) {
// Bank bank1 = new Bank();
// Bank bank2 = new Bank();
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 = bank2);
}
}
// 饿汉式
class Bank{
// 1.私有化类的构造器
private Bank(){
}
//2.内部创建类的对象
//4. 要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共静态的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
2.懒汉式
package com.tyl2.java;
/*
* 单例模式的懒汉式实现
*
*/
public class SingletonTest2 {
public static void main(String[] args) {
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);
}
}
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;
}
}
3.单例模式的优点
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的 产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可 以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方 式来解决。
4.应用场景
网站的计数器,一般也是单例模式实现,否则难以同步。
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
Application也是单例的典型应用
Windows的Task Manager (任务管理器)就是很典型的单例模式
Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例。
二、理解main方法的语法
1.理解main方法的语法
由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须 是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令 时传递给所运行的类的参数。
又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创 建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情 况,我们在之前的例子中多次碰到。
2.代码演示
package com.tyl2.java;
/*
* main()方法的使用说明:
1,main()方法作为程序的入口
2.main()方法也是一个普通的静态方法
3,main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
*
*/
public class MainTest {
public static void main(String[] args) { //入口
Main.main(new String[100]);
// show();
MainTest test1 = new MainTest();
test1.show();
}
public void show(){
}
}
class Main{
public static void main(String[] args) {
// args = new String[100];
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
package com.tyl2.java;
public class MainDemo {
public static void main(String[] args) {
for(int i = 0; i < args.length; i++){
System.out.println("******" + args[i]);
int num = Integer.parseInt(args[i]);
System.out.println("######" + num);
}
}
}
三、类的成员之四:代码块
1.概念
2.代码演示
package com.tyl3.java;
/*
* 类的成员之四:代码块(或初始化块)
*
* 1、代码块的作用:用来初始化类、对象
2、代码块如果有修饰的话,只能使用static
3、分类:静态代码块 VS 非静态代码块
4.静态代码块
>内部可以有输出语句
>随着类的加载而执行,而且只执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优先于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
5.非静态代码块
>内部可以有输出语句
>随着对象的创建而执行
>每创建一个对象,就执行一次非静态代码块
>作用:可以在创建对象时,对对象的嘱性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
*
*
*
*/
public class BlockTest {
public static void main(String[] args) {
String desc = Person.desc;
System.out.println(desc);
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.age);
Person.Info();
}
}
class Person{
// 属性
String name;
int age;
static String desc = "我是一个男人";
// 构造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
// static代码块
static{
System.out.println("hello,static block");
desc = "我很开心!";
}
static{
System.out.println("hello,static block-1");
}
// 非static代码块
{
System.out.println("hello, block");
}
{
System.out.println("hello, block-1");
//调用非static
age = 1;
eat();
//调用static
desc = "2121523";
Info();
}
// 方法
public void eat(){
System.out.println("chifan");
}
public static void Info(){
System.out.println("我要快乐");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
3.静态初始化块举例
package com.tyl3.java;
//总结:由父及子,静态先行
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();
}
}
package com.tyl3.java;
class Father {
static {
System.out.println("11111111111");
}
{
System.out.println("22222222222");
}
public Father() {
System.out.println("33333333333");
}
}
public class Son extends Father {
static {
System.out.println("44444444444");
}
{
System.out.println("55555555555");
}
public Son() {
System.out.println("66666666666");
}
public static void main(String[] args) { // 由父及子 静态先行
System.out.println("77777777777");
System.out.println("************************");
new Son();
System.out.println("************************");
new Son();
System.out.println("************************");
new Father();
}
}
4.属性赋值的位置
package com.tyl3.java;
/*
* 对属性可以赋值的位置:
①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过“对象,属性“或"对象,方法“的方式,进行赋值
执行的先后顺序:①- ②/⑤ -③ -④
*
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.ordId);
}
}
class Order{
int ordId = 3;
{
ordId = 4;
}
}
四、关键字:final
1.概念
2.代码演示
package com.tyl3.java;
/*
* final:最终的
1.fina1可以用来修饰的结构:类、方法、变量
2,fina1用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类
3.fina1用来修饰方法:表明此方法不可以被重写
比如:object类中getC1ass();
4.final用来修饰变量:此时的"变量"就称为是一个常量
4.1、fina1修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
4.2、f1na1修饰局部变量:
尤其是使用fina1修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值
以后,就只能在方法体内使用此形参,但不能进行重新赋值。
*
* static final用来修饰属性:全局常量
*
*/
public class FinalTest {
final int WIDTH = 0;
final int LEFT;
final int RIGHT;
// final int DOWN;
{
LEFT = 2;
}
public FinalTest(){
RIGHT = 3;
}
public FinalTest(int n){
RIGHT = n;
}
// public void setDown(int down){
// this.DOWN = down;
//
// }
public static void main(String[] args) {
FinalTest test = new FinalTest();
// test.setDown(3);
}
}
final class FinalA{
}
//class b extends FinalA{
//
//}
//class C extends String{
//
//}
3.面试题
五、抽象类与抽象方法
1.概念
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一 般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父 类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
2.代码演示
package com.tyl.java;
/*
* abstract关键字的使用
1.abstract:抽象的
2,abstract可以用来修饰的结构:类、方法
3.abstract修饰类:抽象类
>此类不能实例化
>抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
>开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
4.abstract修饰方法:抽象方法
>抽象方法只有方法的声明,没有方法体
>包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
>若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
*
*
*
*/
public class AbstractTset {
public static void main(String[] args) {
//一旦Person类抽象了,就不可实例化
// Person p1 = new Person();
// p1.eat();
}
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//不是抽象方法
// public void eat(){
// }
public abstract void eat(); // 抽象方法
public void walk(){
System.out.println("走路");
}
}
class Student extends Person{
public Student(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println("多吃饭");
}
@Override
public void breath() {
System.out.println("呼吸");
}
}
3.匿名子类对象
package com.tyl.java;
/*
*
*
*
*抽象类的匿名子类
*
*
*
*/
public class PersonTest {
public static void main(String[] args) {
method(new Student()); //匿名对象
Worker worker = new Worker();
method1(worker); // 非匿名的类 非匿名的对象
method1(new Worker()); //非匿名的类 匿名对象
System.out.println("......................................");
//创建一个匿名子类的对象 p
Person p = new Person(){
@Override
public void eat() {
System.out.println("chidongxi");
}
@Override
public void breath() {
System.out.println("呼吸111111");
}
};
method1(p);
System.out.println("......................................");
//创建匿名子类的匿名对象
method1(new Person() {
@Override
public void breath() {
System.out.println("huxisaklsjlaj");
}
@Override
public void eat() {
System.out.println("吃个锤子");
}
});
}
public static void method1(Person p){
p.eat();
p.breath();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
4.多态的应用:模板方法设计模式(TemplateMethod)
4.1、举例
package com.tyl.java;
public class TemplateTest {
public static void main(String[] args) {
Template template = new SubTemple();
template.spendTime();
}
}
abstract class Template{
//计算某段代码执行所需要花费的时间*
public void spendTime(){
long start = System.currentTimeMillis();
this.code(); //不确定的部分、易变的部分
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
}
class SubTemple extends Template{
@Override
public void code() {
for (int i = 2; i <= 1000; i++){
boolean isFlag = true;
for(int j = 2; j <= Math.sqrt(i); j++){
if(i%j==0){
isFlag = false;
break;
}
}
if(isFlag){
System.out.println(i);
}
}
}
}
4.2、举例
package com.tyl.java;
//抽象类的应用:模板方法的设计模式
public class TemplateMethodTest {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
BankTemplateMethod btm2 = new ManageMoney();
btm2.process();
}
}
abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队");
}
public abstract void transact(); // 办理具体的业务 //钩子方法
public void evaluate() {
System.out.println("反馈评分");
}
// 模板方法,把基本操作组合到一起,子类一般不能重写
public final void process() {
this.takeNumber();
this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
this.evaluate();
}
}
class DrawMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要取款!!!");
}
}
class ManageMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要理财!我这里有2000万美元!!");
}
}
5.练习3
编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个 Employee对象的生日,则将该雇员的工资增加100元。
Employee父类
package com.tyl3.java;
/*
* 定义一个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(String name, int number, MyDate birthday) {
super();
this.name = name;
this.number = number;
this.birthday = birthday;
}
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;
}
public abstract double earnings();
@Override
public String toString() {
return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateAString();
}
}
MyDate类
package com.tyl3.java;
/*
* private成员变量year,month,day ;
toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
*/
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = 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;
}
public String toDateAString(){
return year + "年" + month + "月" + day + "日";
}
}
SalariedEmployee子类
package com.tyl3.java;
/*
* 定义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[name: " + super.toString() + "]";
}
}
HourlyEmployee子类
package com.tyl3.java;
/*
* 参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理。
* 该类包括:private成员变量wage和hour;
实现父类的抽象方法earnings(),该方法返回wage*hour值;
toString()方法输出员工类型信息及员工的name,number,birthday。
*/
public class HourlyEmployee extends Employee{
private int wage; // 每小时的工资
private int hour; // 月工作的小时数
public HourlyEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public HourlyEmployee(String name, int number, MyDate birthday, int wage, int hour) {
super(name, number, birthday);
this.wage = wage;
this.hour = hour;
}
@Override
public double earnings() {
return wage * hour;
}
public String toString(){
return "HourlyEmployee[name: " + super.toString() + "]";
}
}
PayrollSystem测试类
package com.tyl3.java;
/*
* 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各
类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类
型,name,number,birthday,当键盘输入本月月份值时,
如果本月是某个Employee对象的生日,还要输出增加工资信息。
*/
import java.util.Calendar;
import java.util.Scanner;
public class PayrollSystem {
public static void main(String[] args) {
//方式一
// Scanner scanner = new Scanner(System.in);
// System.out.println("请输入月份:");
// int month = scanner.nextInt();
//方式二
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH); //获取当前月份
System.out.println(month);
Employee[] emps = new Employee[2];
emps[0] = new SalariedEmployee("马云", 1002, new MyDate(1998, 2, 28),10000);
emps[1] = new HourlyEmployee("神经病", 2001,new MyDate(1999, 4, 10),60,240);
for(int i = 0; i < emps.length; i++){
System.out.println(emps[i]);
double salary = emps[i].earnings();
System.out.println("月工资为:" + salary);
if(month+1 == emps[i].getBirthday().getMonth()){
System.out.println("生日快乐! 奖励一百元");
}
}
}
}
六、接口(interface)
1.概念
2.举例说明
3.举例说明
4.代码
package com.tyl4.java;
/*
* 接口的使用
I,接口使用interface来定义
2,Java中,接口和类是并列的两个结构
3,如何定义接口:定义接口中的成员
* 3,1JDK7及以前:只能定义全局常量和抽象方法
>全局常量,pub1 ic static final的,但是书写时,可以省略不写
>抽象方法,public abstract的
3,2门DK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
*
* 4,接口中不能定义构造器的!意味着接口不可以实例化
*
5,java开发中,接口通过让类去实现(implements)的方式来使用,
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
*
* 6.Java类可以实现多个接口~-~>弥补了Java单继承性的局限性
格式,class AA extends BB implements CC,DD,EE
7.接口与接口之间可以继承,而且可以多继承
*
*
* 8.接口的具体使用,体现多态性
* 9.接口,实际上可以看做是一种规范
*
* 面试题:抽象类与接口有哪些异同?
*/
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
// Flyable.MIN_SPEED = 2;
Plane plane = new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900; //第一宇宙速度
int MIN_SPEED = 1; //省略了public static final
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
// //接口不可以建立构造器Interfaces cannot have constructors
// public Flyable(){
//
// }
}
interface Attackable{
void attack();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("直接起飞");
}
@Override
public void stop() { //implements com.tyl4.java.Flyable.stop
System.out.println("停止起飞");
}
}
abstract class kite implements Flyable{
@Override
public void fly() {
}
}
class Bullet extends Object implements Flyable,Attackable,CC{
@Override
public void attack() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
//.........................................................
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
package com.tyl4.java;
/*
*
* 接口的使用
1.接口使用上也满足多态性
2.接口,实际上就是定义了一种规范
3.开发中,体会面向接口编程!
*/
public class USBTest {
public static void main(String[] args) {
Computer computer = new Computer();
//1,创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
computer.tranferData(flash);
//2,创建了接口的非匿名实现类的匿名对象
computer.tranferData(new Printer());
//3.创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
computer.tranferData(phone);
//4.创建了接口的匿名实现类的匿名对象
computer.tranferData(new USB() {
@Override
public void stop() {
System.out.println("mp5开始工作");
}
@Override
public void start() {
System.out.println("mp5开始工作");
}
});
}
}
class Computer{
public void tranferData(USB usb){ //USB usb = new Flash()
usb.start();
System.out.println("具体传输的细节");
usb.stop();
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开始工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
5.接口的应用:代理模式(Proxy)
1.概述
2.代码
package com.tyl4.java;
/*
* 接口的应用:代理模式
*
*/
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
// server.browse();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
// 被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("联网之前的准备工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
package com.tyl4.java;
public class StaticProxyTest {
public static void main(String[] args) {
Star s = new Proxy(new RealStar());
s.confer();
s.signContract();
s.bookTicket();
s.sing();
s.collectMoney();
}
}
interface Star {
void confer();// 面谈
void signContract();// 签合同
void bookTicket();// 订票
void sing();// 唱歌
void collectMoney();// 收钱
}
class RealStar implements Star {
public void confer() {
}
public void signContract() {
}
public void bookTicket() {
}
public void sing() {
System.out.println("明星:歌唱~~~");
}
public void collectMoney() {
}
}
class Proxy implements Star {
private Star real;
public Proxy(Star real) {
this.real = real;
}
public void confer() {
System.out.println("经纪人面谈");
}
public void signContract() {
System.out.println("经纪人签合同");
}
public void bookTicket() {
System.out.println("经纪人订票");
}
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("经纪人收钱");
}
}
6.【面试题】排错:
package com.tyl4.java;
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
// System.out.println(x);
System.out.println(super.x);
System.out.println(A.x); // x是全局常量
}
public static void main(String[] args) {
new C().pX();
}
}
7.练习4
package com.tyl5.java;
/*
* interface CompareObject{
public int compareTo(Object o);
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
*
*/
public interface CompareObject {
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
public int compareTo(Object o);
}
package com.tyl5.java;
/*
* 定义一个Circle类,声明redius属性,提供getter和setter方法
*
*/
public class Circle {
private Double redius;
public Double getRedius() {
return redius;
}
public void setRedius(Double redius) {
this.redius = redius;
}
public Circle() {
super();
}
public Circle(Double redius) {
super();
this.redius = redius;
}
}
package com.tyl5.java;
/*
* 定义一个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;
// 错误的
// return (int) (this.getRedius() - c.getRedius());
// 正确的
// if (this.getRedius() > c.getRedius()) {
// return 1;
// } else if (this.getRedius() < c.getRedius()) {
// return -1;
// } else {
// return 0;
// }
//当属性radius声明为Double类型时,可以调用包装类的方法
//正确的方式二:
return this.getRedius().compareTo(c.getRedius());
} else {
return 0;
// throw new RuntimeException("传入的数据类型不匹配");
}
}
}
package com.tyl5.java;
public class ComparableTest {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(3.4);
ComparableCircle c2 = new ComparableCircle(3.6);
int compareVlaue = c1.compareTo(c2);
if(compareVlaue > 0){
System.out.println("c1对象大");
}else if(compareVlaue < 0){
System.out.println("c2对象大");
}else {
System.out.println("一样大");
}
int compareVlaue1 = c1.compareTo(new String("AA"));
System.out.println(compareVlaue1);
}
}
8.接口和抽象类之间的对比
9.Java 8中关于接口的改进
1.概述
接口中的默认方法
2..代码
package com.tyl8.java;
/*
* JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
*
*/
public interface ComA {
//静态方法
public static void method1(){
System.out.println("66666");
}
//默认方法
public default void method2(){
System.out.println("111111");
}
default void method3(){
System.out.println("111111");
}
}
package com.tyl8.java;
public interface ComB {
default void method3(){
System.out.println("ComB!!!!");
}
}
package com.tyl8.java;
public class SuperClass {
public void method3(){
System.out.println("SuperClass! 西安");
}
}
package com.tyl8.java;
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// s.method1();
// SubClass.method1();
//知识点1:接口中定义的静态方法,只能通过接口来调用。
ComA.method1();
//知识点2:通过实现类的对象,可以调用接口的默认方法
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以局的方法
s.method2();
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法 >>>>类优先原则
s.method3();
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没有重写此方法的情况下,报错。---->接口冲实。
//这就需要我们必须在实现类中重写此方法
}
}
class SubClass extends SuperClass implements ComA,ComB{
@Override
public void method2() {
System.out.println("SubClass!!!!");
}
public void method3() {
System.out.println("!!!!!!!!!!");
}
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3(); //调用自己定义的重写的方法
super.method3(); //调用的是父类中声明的
//调用接口中的默认方法
ComA.super.method3();
ComB.super.method3();
}
}
七、类的成员之五:内部类
1.概述
2.代码
package com.tyl9.java;
import com.tyl9.java.Person.Dog;
/*
* 类的内部成员之五:内部类
1,JaVa中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2,内部类的分类,成员内部类(静态、非静态)VS局部内部类(方法内、代码块内、构造器内)
3.成员内部类:
一方面,作为外部类的成员,
>调用外部类的结构
>可以被static修饰
>可以被4种不同的权限修饰
另一方面,作为一个类:
>类内可以定义属性、方法、构造器等
>可以被Final修饰,表示此类不能被继承。言外之意,不使用fina1,就可以被继承
>可以被abstract修饰
*
* 4.关注如下的3个问题
4,1 如何实例化成员内部类的对象
4,2 如何在成员内部类中区分调用外部类的结构
4,3 开发中局部内部类的使用 见《InnerclassTest1.java》
*/
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类):
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println("...................");
bird.display("黄历");
}
}
class Person{
String name = "xaiohong";
int age;
public void eat(){
System.out.println("干饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("卡拉是条狗");
}
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public void sing(){
System.out.println("鸟");
Person.this.eat(); //调用外部类的静态属性
}
public void display(String name){
System.out.println(name); //方法的形参
System.out.println(this.name); //内部类的属性
System.out.println(Person.this.name); //外部类的属性
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class CC{
}
}
}
package com.tyl9.java;
public class InnerClassTest1 {
public void method4(){
//局部内部类
class AA{
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一
// 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;
}
};
}
}
3.局部内部类使用的一个注意点
package com.tyl.java;
/*
* 在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法
* (比如:method)中的局部变量(比如:num)
要求此局部变量声明为final的。
jdk7及之前版本:要求此局部变量显式的声明为final的
jdk8及之后的版本:可以省略final的声明
*
*/
public class InerrClassTest {
public void method(){
//局部变量
int num = 10;
class AA{
public void show(){
System.out.println(num);
}
}
}
}
东西真的多,累死了!!! 啊啊啊啊啊啊啊