尚硅谷java入门(303p- 346p)2022.3.17 面向对象(下)

303p 基本数据类型转换为包装类

public class WrapperTest{
//String类型--->基本数据类型,包装类:调用包装类的parseXxx()
@Test
public void test5(){
  String str1="123";
  //Interger in1=(Integer)str1;
  //可能会报NumberFormatExpection
  int num2=Integer.parseInt(str1);
  System.out.println(num2+1);
  String str2="true";
  boolean b1=Boolean.parseBoolean(str2);
  System.out.println(b1);
}
//基本数据类型,包装类转换为String类:调用String重载的valueOf(XXX xxx)
@Test
public void test4(){
    int num1=10;
    //方式一:连接运算
    String str1=num+"";
    //方式二:调用String的valueOf(XXX xxx)
    float f1=12.3f;
    String str2=String.valueOf(f1);//"12.3"
    
    Double d1=new Double(12.4);
    String str3=String.valueOf(d1);
    System.out.println(str2);
    System.out.println(str3);
}
//JDK 5.0新特性:自动装箱与自动拆箱
@Test
public void test3(){
   int num1=10;
   //基本数据类型转化为包装类的对象
   method(num1);
   //自动装箱:基本数据类型转化为包装类
   int num2=10;
   Integer in1=num2;
   boolean b1=true;
   Boolean b2=b1;
   //自动拆箱:包装类转换为基本数据类型
   System.out.println(in1.toString());
   int num3=in1;
}
public void method(Object obj){
   System.out.println(obj);
}
//包装类转换为基本数据类型:调用包装类的xxxValue
    @Test
    public void test2(){
        Integer in1=new Integer(12);
        int i1=in1.intValue();
        System.out.println(i1+1);
        Float f1=new Float(12.3);
        float f2=f1.flaotValue();
        System.out.println(f2+1);
    }
//基本数据类型--》包装类,调用包装类的构造器
	@Test
	public void test1() {
		int num1 = 10;
//		System.out.println(num1.toString());
		
		Integer in1 = new Integer(num1);
		System.out.println(in1.toString());
		
		Integer in2 = new Integer("123");
		System.out.println(in2.toString());
		
		//报异常
//		Integer in3 = new Integer("123abc");
//		System.out.println(in3.toString());
		
		Float f1 = new Float(12.3f);
		Float f2 = new Float("12.3");
		System.out.println(f1);
		System.out.println(f2);
        Boolean b1=new Boolean(true);
        Boolean b1=new Boolean("true");
        Boolean b1=new Boolean("true123");
        System.out.println(b3);//false
        Order order=new Order();
        System.out.println(order.isMale);//false
        System.out.println(order.isFemale);//null
        
}
}
class Order{
    boolean isMale;
    Boolean isFemale;
}

307 包装类常见面试题

如下两个题目输出结果相同吗?各是什么:
 *         Object o1= true? new Integer(1) : new Double(2.0);
 *         System.out.println(o1);//
 * 
 *         Object o2;
 *         if(true)
 *             o2 = new Integer(1);
 *        else 
 *            o2 = new Double(2.0);
 *        System.out.println(o2);//
 

public class InterViewTest {

	@Test
	public void test1(){
		Object o1= true? new Integer(1) : new Double(2.0);
		System.out.println(o1);// 1.0
	}
	
	@Test
	public void test2(){
		Object o2;
		if(true)
			o2 = new Integer(1);
		else 
			o2 = new Double(2.0);
		System.out.println(o2);// 1
	}
@Test
	public void method1() {
		Integer i = new Integer(1);
		Integer j = new Integer(1);
		System.out.println(i == j); //false
		
	    //Integer内部定义了一个IntegerCache结构,IntegerCache中定义Integer[]
		//保存了从-128-127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在其中时,
		//可以直接使用数组中的元素,不用再去new了。目的,提高效率。
		
		Integer m = 1;
		Integer n = 1;
		System.out.println(m == n);//true
		
		Integer x = 128;//相当于new了一个Integer对象
		Integer y = 128;//相当于new了一个Integer对象
		System.out.println(x == y);//false

	}
}

308 包装类的课后练习 

public class ScoreTest{
    public static void main(String[] args){
       //1.实例化Scanner,用于从键盘获取学生成绩
       Scanner scan=new Scanner(System in);
       //2.创建Vector对象,Vector v=new Vector();相当于原来的数组
       Vector v=new Vector();
       //3.通过for(;;)或while(true)方式,给Vector中添加数组
       int maxScore=0;
       for(;;){
           System.out.println("请输入学生成绩(以负数代表输入结束)");
           int score=scan.nextInt();
           if(score<0){
               break;
           }
           if(score>100){
               System.out.println("输入的数据非法,请重新输入");
               continue;
           }
           //3.1 添加操作:v.addElement(Object obj)
           //jdk5.0之前
           Integer inScore=new Integer(score);
           v.addElement(inScore);//多态
           //jdk5.0之后
           v.addElement(score);//自动装箱
           //4.获取学生成绩的最大值
           if(maxScore<score){
               maxScore=score;
           }
       }
       //5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级
       for(int i=0;i<v.size();i++){
           Object obj = v.elementAt(i);
           //jdk5.0之前
           Integer inScore=(Integer)obj;
           int score=inScore.intValue();
           //jdk5.0之后
           int score=(int)obj;
           if(maxScore-score<=10){
                level='A';
           }else if(maxScore-score<=20){
                level='B';
           }else if(maxScore=score<=30){
                level='C';
           }else{
                level='D';
           }
           System.out.println("student-"+i+"score is"+score+",level is"+level);
           
       }
   }
}

313 static关键字的引入

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过 new 关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。

我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。

例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。

314 静态变量与实例变量的对比 

 static关键字的使用

1.static:静态的

2.static可以用来修饰:属性,方法,代码块,内部块

3.使用static修饰属性

静态变量按是否使用static修饰,又分为:静态属性vs非静态属性(实例变量)

实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改

静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的

4.使用static修饰方法

public class StaticTest{
      public static void main(String[] args){
            Chinese.nation="中国";
            Chinese c1=new Chinese();
            c1.name="姚明";
            c1.age=40;
            c1.nation="CHN";
            Chinese c2=new Chinese();
            c2.name="马龙";
            c2.age=30;
            c2.nation="CHINA";
            System.out.println(c1.nation);
      }
}
class Chinese{
   String name;
   int age;
   static String nation;
}

 315 static修饰属性的其他说明

1.静态变量随着类的加载而加载,可以通过“类.静态变量”的方式进行调用

2、静态变量的加载要早于对象的创建

3.由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中

4.                      类变量             实例变量

类                        yes                  no

对象                     yes                   yes

316 类变量和实例变量的内存解析

 静态属性举例:System.out

Math.PI

317  static 修饰方法

静态方法特点

1.随着类的加载而加载,可以通过“类.静态方法”的方式进行调用

2.

                            静态方法         非静态方法

类                        yes                  no

对象                     yes                   yes 

 3.静态方法中,只能调用静态的方法或属性,对于非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

4.static注意点

4.1在静态的方法内,不能使用this关键字,super关键字

4.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解

318 属性或方法是否应该static的经验之谈

开发中,如何确定一个属性是否要声明为static的?

1.属性是可以被多个对象所共享的,不会随着对象的不同而不同的

2.类中的常量也通常声明为static

开发中,如何确定一个方法是否要声明为static的?

1.操作静态属性方法,通常设置为static的

2.工具类的方法,习惯上声明为static的。比如,Math,Arrays,Collection

319 自定义ArrayUtil工具类的优化

/*
 * 自定义数组工具类
 */
public class ArrayUtil {

	// 求数组的最大值
	public static int getMax(int[] arr) {
		int maxValue = arr[0];
		for (int i = 1; i < arr.length; i++) {
			if (maxValue < arr[i]) {
				maxValue = arr[i];
			}
		}
		return maxValue;
	}

	// 求数组的最小值
	public static int getMin(int[] arr) {
		int minValue = arr[0];
		for (int i = 1; i < arr.length; i++) {
			if (minValue > arr[i]) {
				minValue = arr[i];
			}
		}
		return minValue;
	}

	// 求数组总和
	public static int getSum(int[] arr) {
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
			sum += arr[i];
		}
		return sum;
	}

	// 求数组平均值
	public static int getAvg(int[] arr) {
		int avgValue = getSum(arr) / arr.length;
		return avgValue;
	}

	//如下两个同名方法构成重载
	// 反转数组
	public static void reverse(int[] arr) {
		for (int i = 0; i < arr.length / 2; i++) {
			int temp = arr[i];
			arr[i] = arr[arr.length - i - 1];
			arr[arr.length - i - 1] = temp;
		}
	}
	
	public void reverse(String[] arr){
		
	}

	// 复制数组
	public static int[] copy(int[] arr) {
		int[] arr1 = new int[arr.length];
		for (int i = 0; i < arr1.length; i++) {
			arr1[i] = arr[i];
		}
		return null;
	}

	// 数组排序
	public static void sort(int[] arr) {
		for (int i = 0; i < arr.length - 1; i++) {
			for (int j = 0; j < arr.length - 1 - i; j++) {
				if (arr[j] > arr[j + 1]) {
//					int temp = arr[j];
//					arr[j] = arr[j + 1];
//					arr[j + 1] = temp;
					//错误的:
//					swap(arr[j],arr[j+1]);
					
					swap(arr,j ,j+1);
				}
			}
		}
	}
	
	//错误的:交换数组中两个指定位置元素的值
//	public void swap(int i,int j){
//		int temp = i;
//		i = j;
//		j = temp;
//	}
	
	//正确的:
	private static void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}

	// 遍历数组
	public static void print(int[] arr) {
		System.out.print("[");
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + ",");
		}
		System.out.println("]");
	}

	// 查找指定元素
	public static int getIndex(int[] arr, int dest) {
		//线性查找
		for (int i = 0; i < arr.length; i++) {

			if (dest==arr[i]) {
				return i;
			}

		}
		return -1;
	}

}

320 static应用举例 

public class CircleTest{
   public static void main(String[] args){
          Circle c1=new Circle();
          Circle c2=new Circle();
          System.out.prinln("c1的id:"+c1.getId());
          System.out.prinln("c2的id:"+c2.getId());
          System.out.prinln("创建的圆的个数为:"+Circle.getTotal());
}
class Circle{
       private double radius;
       private int id;//自动赋值
       public Circle(){
           id=init++;
           total++;
       }
       public Circle(double radius){
           this.radius=radius;
           id=init++;
           total++;
       }
       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 void setId(int id){
          this.id=id;
       }
       public static int getTotal(){
          return total;
       }
}

321 课后练习:账户信息

/*
 * 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、
 * “利率”、“最小余额”,定义封装这些属性的方法。
 * 账号要自动生成。编写主类,使用银行账户类,输入、输出 3 个储户的上述信息。
 * 考虑:哪些属性可以设计成 static 属性。
 * 
 */
public class Account{
     private int id;
     private String pwd="000000";
     private double balance;
     private static double interestRate;
     private static double minMoney=1.0;
     private static double init=1001;
     public Account(){
          id=init++;
      }
     public Account(String pwd,double balance){
          id=init++;
          this.pwd=pwd;
          this.balance=balance;
     public void setPwd(String pwd){
          this.pwd=pwd;
     }
     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;
     }
     public int getId(){
        return id;
     }
     public double getBalance(){
        return balance;
     }
     public String toString(){
        return "Account [id="+id+",pwd"+pwd+",balance="+balance+"]";
     }

public class AccountTest{
     public static void main(String[] args){
         Account  acct1=new Account();
         Account acct2=new Account("qwerty",2000);
         Account.setInterestRate(0.012);
         Account.setMinMoney(100);
         
         System.out.println(acct1);
         System.out.println(acct2);
         System.out.println(acct1.getInterestRate());
         System.out.println(acct1.getMinMoney());
         
     }
}
        

322 设计模式与单例设计模式 

 设计模式是**在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。**设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。”套路”

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为 private,这样,就不能用 new 操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。

323 单例的饿汉式实现

1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例

2.如何实现

public class SingletonTest1{
      public static void main(String[] args){
      Bank bank1=Bank.getInstance();
      Bank bank2=Bank.getInstance();
      System.out.println(bank1==bank2);//true
      }
}
//饿汉式
class Bank{
   //1.私有化的构造器
   private Bank(){
   }
   //2.内部创建类的对象
   //4.要求此对象也必须声明为静态的
   private static Bank instance=new Bank();
   //3.提供公共的静态的方法,返回类的对象
   public static Bank getInstance(){
        return instance;
   }
}

324 单例的懒汉式实现

public class SingletonTest2{
   public static void main(String[] args){
         Order order1=Order.getInstance();
         Order order2=Order.getInstance();
         System.out.println(order1==order2);//true
   }
}
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;
   }
}

325 饿汉式和懒汉式的对比

饿汉式:坏处:对象加载时间过长

好处:饿汉式是线程安全的

懒汉式:好处:延迟对象的创建

    目前的写法坏处:线程不安全---->到多线程内容时,再修改

326 单例模式的使用场景

由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

单例模式应用场景 

1、网站的计数器,一般也是单例模式实现,否则难以同步。


2、应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

3、数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。


4、项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。


5、Application也是单例的典型应用


6、Windows 的 **Task Manager (任务管理器)**就是很典型的单例模式


7、Windows 的 **Recycle Bin(回收站)**也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

327 理解main()方法的语法

main()方法的使用说明

1.main()方法作为程序的入口

2.main()方法也是一个普通的静态方法

3.main()方法可以作为我们与控制台交互的方式(之前,使用Scanner)

public class MainTest{
   public static void main(String[] args){//入口
    Main.main(new String[100]);
    show();
}
  public void show(){
  }
}
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]);
   }
  }
}

public class MainDemo{
   public static void main(String[] args){
     for(int i=0;i<args.length;i++){
       System.out.println("***********"+args[i]);
       int num=Integar.parseInt(args[i]);
       System.out.println("############"+num);
    }
    
}
}

328 类中代码块结构的使用

 类的成员之四:代码块(或初始化块)

1.代码块的作用:用来初始化类,对象

2.代码块如果有修饰的话,只能使用static

3.分类:静态代码块    非静态代码块

4.静态代码块

    内部可以有输出语句

   随着类的加载而执行,而且只执行一次

   作用:初始化类的信息

   如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行

    静态代码块的执行要优先于非静态代码块的执行

    静态代码块内只能调用静态的属性,静态的方法,不能调用非静态的结构

5.非静态代码块

    内部可以有输出语句

   随着对象的创建而执行

   每创建一个对象,就执行一次非静态代码块

   作用:可以在创建对象时,对对象的属性等进行初始化

   如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行

    非静态代码块内可以调用静态的属性,静态的方法,或非静态的属性,非静态的方法

对属性可以赋值的位置:

1.默认初始化

2.显式初始化

3.构造器中初始化

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();
}
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-1");
    desc="我是一个爱学习的人";
  }
  static{
    System.out.println("hello,static block-2");
    
  }
  //非static的代码块
  {
     System.out.println("hello,block");
  }
  //方法
  public void eat(){
      System.out.println("吃饭");
  }
  public String toString(){
      return "Person [name"+name+",age="+age+"]";
  }
  public static void info(){
      System.out.println("我是一个快乐的人");
  }
}

329 开发中代码块的使用举例 

330 代码块的课后练习

//总结:由父类到子类,静态先行
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(); 
		//new Leaf();
	}
}
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();
	}

}

331 属性赋值的先后顺序(完结篇)

public class Ordertest{
   public static void main(String[] args){
        Order order=new Order();
        System.out.println(order.orderId);
     }
}
class Order{
     int orderId=3;
     {
        orderId=4;
     }
}

 

332 final修饰类和方法 

1. final可以用来修饰的结构:类,方法,变量

2,final可以用来修饰一个类:此类不能被其他类所继承

            比如:String类,System类,StringBuffer类

3.final用来修饰方法:表明此方法不可以重写

          比如:Object类中getClass();

public class FinalTest{
}
final class FinalA{
}

333 final修饰属性 

4.    final  用来修饰变量:此时的“变量”就称为是一个常量

       4.1 final修饰属性:可以考虑赋值的位置有

                                    显式初始化

                                    代码块中初始化

                                    构造器中初始化

public class FinalTest{
    final int width=10;
    final int LEFT;
    final int RIGHT;
    //final int down;
    {
       LEFT=1;
    }
    public FinalTest(){
       Right=2;
    }
    public FinalTest(int n){
       Right=n;
    }
    //public void setDown(int down){
    //       this.down=down;
    //}
    public void doWidth(){
       //   width=20;
    }
}

334 final修饰局部变量 

public void show(){
     final int NUM=10;//常量
}
public void show(final int num){
    System.out.println(num);
}

4.2final修饰局部变量

尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值 

static final 用来修饰属性:全局常量

335 final课后练习

public class Something {
	public int addOne(final int x) {
		return ++x;//错误原因:既返回,又加一 
       // return x + 1;//只有加一的操作
	}
}
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;
}

341 抽象类与抽象方法的使用

 随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

abstract关键字的使用

1.抽象的

2.可以用来修饰的结构:类,方法

3.abstract修饰类:抽象类

       此类不能实例化

      抽象类中一定有构造器,便于子类对象实例化时调用(涉及:子类对象实例化的全过程)

      开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

4,abstract修饰方法:抽象方法

      抽象方法只有方法的声明,没有方法体

     包含抽象方法的类,一定是一个抽象类,反之,抽象类中可以没有抽象方法的

     若子类重写了父类中的所有的抽象方法后,此子类方可实例化

     若子类没有重写父类中的所有的抽象方法后,则此子类也是一个抽象类,需要用abstract来修饰

public class AbstractTest{
   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){
       this.name=name;
       this.age=age;
   }
   public void eat(){
      System.out.println("人吃饭");
   }
   //抽象方法
   public abstract void eat();
   public void walk(){
      System.out.println("人走路");
   }
   
}
class Student extends Person{
  public Student(String name,int age){
       super(name,age);
 }
 public void eat(){
  System.out.println("学生应该多吃有营养的食物");
 }
 public void breath(){
     System.out.println("学生应该呼吸新鲜的空气");
 }
}

342 抽象的应用场景举例 

 

问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle 类不能提供计算方法,但子类可以。

/* Java 允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提  供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
 * Vehicle 是一个抽象类,有两个抽象方法。
 * 注意:抽象类不能实例化 new Vihicle()是非法的
 */
public abstract class Vehicle{
	public abstract double calcFuelEfficiency();//计算燃料效率的抽象方法
	public abstract double calcTripDistance();//计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
	public double calcFuelEfficiency(){ 
		//写出计算卡车的燃料效率的具体方法
	}
	public double calcTripDistance(){ 
		//写出计算卡车行驶距离的具体方法
	}
}
public class RiverBarge extends Vehicle{
	public double calcFuelEfficiency() { 
		//写出计算驳船的燃料效率的具体方法
	}
	public double calcTripDistance( )  {  
		//写出计算驳船行驶距离的具体方法
	}
}

343 abstract使用中的注意点

1.abstract不能用来修饰:属性,构造器等结构

2.abstract不能用来修饰私有方法,静态方法,final的方法,final的类

344 练习:基本操作

 编写一个 Employee 类,声明为抽象类,
 * 包含如下三个属性:name,id,salary。
 * 提供必要的构造器和抽象方法:work()。
 * 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
 * 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
 * 要求类中提供必要的方法进行属性访问。

public class Employee{
    private String name;
    private int id;
    private double salary;
    public Employee(){
        super();
    }
    public Employee(String name,int id,double salary){
        super();
        this.name=name;
        this.id=id;
        this.salary=salary;
    }
    public abstract void work();
}

public class Manager extends Employee{
  private double bonus;
  public Manager(double bonus){
     super();
     this.bonus=bonus;
  }
  public Manager(String name,int id,double salary,double bonus){
     super(name,id,salary);
     this.bonus=bonus;
  }
  public void work(){
    System.out.prinln("管理员工,提供公司运行的效率");
  }
}

public class CommonEmployee extends Employee{
   public void work(){
     System.out.println("员工在一线车间生产产品");
   }
}
public class Employee{
    public static void main(String[] args){
     //多态
     Employee manager=new Manager("库克",1001,5000,50000);
     manager.work();
     CommonEmployee commonEmployee=new CommonEmployee();
     commonEmployee.work();
}
}

345 创建抽象类的匿名子类对象 

public class PersonTest{
     public static void main(String[] args){
         method(new Student());//匿名对象
         Worker worker=new Worker();
         method1(worker);//非匿名的类非匿名的对象
         method1(new Worker());//非匿名的类匿名的对象
         //创建了一匿名子类的对象:p
         Person p=new Person(){
            public void eat(){
               System.out.println("吃东西");
            }
            public void breath(){
               System.out.println("呼吸");
            }
         };
         method1(p);
         //创建匿名子类的匿名对象
         method1(new Person(){
             public void eat(){
               System.out.println("吃东西");
            }
            public void breath(){
               System.out.println("呼吸");
            }
        });
      }
  }
   public static void method(Person p){
         p.eat();
         p.breath();
   }
   public static void method(Student s){
 }
}

class Worker extends Person{
}
public void eat(){
  System.out.println("吃东西");
}
public void breath(){
  System.out.println("呼吸");
}

346 模板方法的设计模式及应用场景 

 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

public class Templatetest{
    public static void main(String[] args){
       SubTemplate t=new SubTemplate();
       t.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 SubTemplate extends Template{
    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);
            }
          }
     }
}
}
//抽象类的应用:模板方法的设计模式
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 万美元!!");
	}
}

模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子,比如常见的有:

 数据库访问的封装

Junit 单元测试

JavaWeb 的 Servlet 中关于 doGet/doPost 方法调用

Hibernate 中模板程序

Spring 中 JDBCTemlate、HibernateTemplate 等

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

京与旧铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值