前言
我现在虽然学了很多Java知识,包括框架,分布式架构之类的,但是基础部分较为薄弱。
恰逢Java作业要写实验报告,我趁此机会复习下Java基础部分,顺便以此博客为记,当作复习之用。
一、实验内容
1.模拟人开车的问题:请同学们各自讨论,独立完成。
模拟人开车:
1.根据模拟开车这问题,给出所需的类;
2.模拟中人如何作用于车对象?
3.模拟中车加速等细节代码,用类似打印“车加速中…”的简易代码。
实验报告至少涉及以下知识点的测试案例
1.为什么说构造方法是一种特殊的方法?特殊在哪里?构造方法什么时候执行?被谁调用?
2.创建类的实例时,是构造方法先运行还是成员变量的初始化先处理? 3.重载? 4.this的应用?
5.private所修饰的变量和方法使用有啥限制?另一对象如何使用另一对象的private变量? 6.如何统计一个类创建的对象数?
7.如果一个类里定义的构造方法都是私有的,如何创建该类的对象?
二、类图/类关系图
思路解析:
无论是奔驰车和奥迪车都有个父类Car,Car中抽象出两个子类的公共部分,包括加速、减速、按喇叭等方法。同时Car和驾驶员Person类存在关系:Car关联了Person,用于模拟人坐进车的情景;Person又依赖于Car,这体现在方法参数的传递上,用来模拟人与车的关系。当Person使用某种方法时,其方法内部会调用Car的对应方法,虽然这在程序设计上有些问题,但是这很好地模拟了人操作车这么一个情景。
另外,对于类的创建上,AudiCar,BenzCar类都重写了父类的构造方法,在原先的基础上会输出相应的语句以示区别。同时AudiCar采用了单例模式——构造方法私有,但是内部维护了一个静态instance属性,当要获取该类示例时,只需调用getInstance方法即可。
至于统计车的数量,这里采用在父类Car中维护一个静态属性的方法记录数据,每当创建一个Car实例时该属性都会自增1,变相达到目的,但是需要注意的是,此属性只是记录创建了多少个Car对象,而不是记录当前内存中存在多少个Car对象,因为有些无用的Car对象会被GC回收,这是我们无法操控的。
三、程序与测试
1.代码部分
Car类
package com.dreamchaser.work2; public class Car { private int speed=0; private String status; //创建的对象数 public static int number=0; //全部汽车摁喇叭的次数 public static int horn=0; //车内驾驶员 private Person person=null; public Car() { System.out.println("创建了辆小车!"); number++; } public void setPerson(Person person) { this.person = person; } public void accelerate(int s){ status="车正在加速中..."; speed+=s; System.out.println(status+"速度飙到"+speed+"迈了!"); } public void slow(int s){ status="车正在减速中..."; speed-=s; if (speed<0){ status="小车正在倒车..."; }else if (speed==0){ status="小车停了!"; }else{ System.out.println("小车正在缓慢前进 "); } System.out.println(status+"速度减到"+speed+"迈了!"); } public void honkHorn(){ System.out.println("车喇叭滴了一声..."); horn++; } public int getSpeed() { return speed; } public String getStatus() { return status; } public static int getNumber() { return number; } public static int getHorn() { return horn; } }
AudiCar类
package com.dreamchaser.work2; public class AudiCar extends Car{ String Logos="奥迪"; //全球首发,仅限一辆(单例模式) private static AudiCar instance=new AudiCar(); //私有构造函数 private AudiCar(){ System.out.println("再加个奥迪车标!"); } public static AudiCar getInstance(){ return instance; } public void showLogos(){ System.out.println("奥迪车标!!!"); } }
BenzCar类
package com.dreamchaser.work2; public class BenzCar extends Car { public BenzCar() { System.out.println("创建小车再加个奔驰车标!"); } //构造函数默认先会调用super(如果没有super的话) public BenzCar(int speed, String status) { System.out.println("再加个奔驰车标!"); } @Override public void honkHorn() { System.out.println("奔驰的喇叭就是不一样"); } }
Person类
package com.dreamchaser.work2; public class Person { private String name; public Person(String name) { this.name = name; } public void accelerate(Car car,int s){ car.accelerate(s); } public void slow(Car car,int s){ car.slow(s); } public void honkHorn(Car car){ car.honkHorn(); } }
Main类
package com.dreamchaser.work2; public class Main { public static void main(String[] args) { //创建小车 Car car=new Car(); BenzCar benzCar=new BenzCar(); AudiCar audiCar=AudiCar.getInstance(); Person person=new Person("张三"); Person benzPerson=new Person("李四"); Person audiPerson=new Person("王五"); //人上小车 car.setPerson(person); benzCar.setPerson(benzPerson); audiCar.setPerson(audiPerson); //人对车进行操作 person.accelerate(car,12); person.honkHorn(car); person.slow(car,12); benzPerson.accelerate(benzCar,70); benzPerson.honkHorn(benzCar); benzPerson.slow(benzCar,66); audiPerson.accelerate(audiCar,70); audiPerson.honkHorn(audiCar); audiPerson.slow(audiCar,66); System.out.println("工厂造了"+Car.number+"辆车!"); System.out.println("奔驰车:"+"number:"+BenzCar.getNumber()+";born:"+BenzCar.getHorn()); System.out.println("奥迪车:"+"number:"+AudiCar.getNumber()+";born:"+AudiCar.getHorn()); System.out.println("普通小车:"+"number:"+Car.getNumber()+";born:"+Car.getHorn()); } }
2.测试结果
四、本章相关知识点程序与测试
1.为什么说构造方法是一种特殊的方法?特殊在哪里?构造方法什么时候执行?被谁调用?
Java在类里提供了一个特殊的成员函数,叫做构造函数。
一个构造函数是对象被创建时初始对象的成员函数。它具有和它所在的类完全一样的名字。一旦定义好一个构造函数,创建对象时就会自动调用它。构造函数没有返回类型,即使是void类型也没有。这是因为一个类的构造函数的返回值的类型就是这个类本身。构造函数的任务是初始化一个对象的内部状态,所以用new操作符创建一个实例后,立刻就会得到一个清楚、可用的对象。
构造函数一般是在创建对象时执行调用。
由创建对象的程序来调用。
2.创建类的实例时,是构造方法先运行还是成员变量的初始化先处理?
成员变量初始化先处理,由上面代码可以看出最终对象的成员变量是构造函数中处理的值,即构造函数中操作成员变量把原先的赋值给覆盖了。
说明成员变量的初始化先处理,构造方法后行。
实际上,由jvm的运行机制也可以看出——Java把.java文件编译成.class后采取双亲委派机制把类加载进jvm内存中,首先是加载每个类的静态属性和方法,然后当程序要用到或者创建对象时会先初始化成员变量,再执行构造函数方法。
3.重载?
重载,从简单说,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。在java中同一个类中的2个或2个以上的方法可以有同一个名字,只要它们的参数声明不同即可。这种情况下,该方法就被称为重载,这个过程称为方法重载 ,通俗的讲就是省了给method命名了.差不多的都用一个.
方法重载的主要好处就是,不用为了对不同的参数类型或参数个数,而写多个函数。多个函数用同一个名字,但参数表,即参数的个数或(和)数据类型可以不同,调用的时候,虽然方法名字相同,但根据参数表可以自动调用对应的函数。
4.this的应用?
this实际上是一个指针(尽管Java中没有指针的概念),用于在对象内部调用时指明自身,最常用的场景就是初始化对象内部状态(构造函数)和复杂方法中参数和自身的区分。
5.private所修饰的变量和方法使用有啥限制?另一对象如何使用另一对象的private变量?
private修饰的成员变量或方法为私有变量或方法,即其他程序无法直接获取成员变量。
此时我们可以通过编写get、set方法来间接让外部获取。
6.如何统计一个类创建的对象数?
首先,明确一个问题,此种情景并不常见,因为Java有内存回收机制,一些不常用的对象会被自动回收,所以统计对象数存在不可靠性。
我们可以通过在类中设置一个静态变量(默认为0),每当调用一次构造函数时,该变量+1(所有对象共享该静态变量,此共享的意思是对象可以操作此静态变量,但是无法通过对象来获取此变量)
7.如果一个类里定义的构造方法都是私有的,如何创建该类的对象?
如上述代码创建奥迪汽车,构造方法私有,但是该类本身维护一个静态变量instance,当要获取对象时直接调用getInstance()方法获取即可。这样的好处就是程序不用频繁创建对象,节省内存,提高运行效率,同时保证每次获取的对象都是同一个。(单例模式)但其适用场景有限制,对于一些不适用单例的场景,此方法并不适用。
当然也可以采用享元模式,调用clone()方法来返回对象的公共部分,这样返回的对象便是一个独立的对象,但也会耗费少量内存和时间(享元模式)
总结
类和对象是Java语言的核心,理解其运行机制,尤其是理解其内在原理对以后探究深层次问题将会大有裨益。