Java类和对象
类
面向对象和面向过程
- 面向对象:Object Oriented
把系统中需要处理的数据和这些数据上的操作结合在一起,根据功能、性质、作用等因素组成不同的数据类型。这种抽象数据类型就被成为“类”。
对象就是类的实例,就是具体的某个实际类。 - 面向过程:Procedure Oriented
类和对象
比如:
类:鸟类
对象:白鹭
- 在Java中万事万物都是类(除了8个值类型)
- 对象依赖于类存在(模板-个体实例)
- 在程序中应该使用的是对象
- 分析过程先有对象后有类,开发过程先有类后有对象
类的基本构成
类主要由以下两点构成
属性:field
属性就是状态,是用于区分不同的实例的。方法/函数:method
方法就是行为,是所有实例都拥有的。
例:
/*定义学生类*/
class Student
{
String name; //姓名
int age; //年龄
float weight; //体重
/*吃饭的方法*/
void dining()
{
System.out.println("吃饱了...");
weight++;
}
/*走路的方法*/
void walk()
{
System.out.println("走累了...");
weight--;
}
}
对象
对象具有三个特征:
- 对象的行为:可以对对象施加哪些操作,或可以对对象施加哪些方法(方法)
- 对象的状态:当施加那些方法时,对象如何响应(属性)。对象状态的改变必须通过调用方法实现(如果不经过方法调用就可以改变对像状态,只能说明封装性遭到了破坏)
- 对象的标识:如何辨别具有相同行为与状态的不同对象(实例名)
面向对象的三大特征
面向对象最重要的三大特征是:封装、继承、多态
封装
- 将某些东西包装在一起,然后以新的完整形式呈现出来;
- 隐藏属性、方法或实现细节的处理方式称为封装;
- 封装其实就是有选择性地公开或隐藏某些信息,它解决了数据的安全性问题。
封装的特性能够让服务提供者把它服务的细节隐藏掉,你只需要提交请求与传递它需要的参数,它就会给你返回结果,而这个结果是如何产生的,经过了多少复杂运算,经过多少次数据读取,你都不用管,只要它给你结果就好了。
继承
继承就是重用现有的类来生成新类的一种特征;
通俗地讲就是从现有的类(即父类或基类)创建新类(子类或派生类)的过程;
现实生活中,继承可以达到财产重用的目的,而在Java中,继承可以使代码重用。
多态:
多态是指同一函数在不同的类中有不同的实现;多态的好处就是使类更灵活,更便于扩充。
类的声明
基础声明形式
[访问权限修饰符][修饰符] class 类名{
成员列表
}
如:public final class Bike{}
1. 访问权限修饰符:
- public:公有的,完全公开的。
- protected:本包和所有子类。
- private:私有的,不公开的。
- default:默认的。
2. 类命名规则
- 由大写字母开头而单词中的其他字母均为小写;如果类名称由多个单词组成,则每个单词的首字母均应为大写,把这些单词连接在一起,即不要使用下划线分割单词,例如:OrderList。————驼峰式
- 如果类名称中包含单词缩写,则这个所写词的每个字母均应大写,如:XMLExample
- 由于类是设计用来代表对象的,所以在命名类时应尽量选择名词。 如上例的: Bike
3. 修饰符
- final
- abstract
- native
类成员属性、初始化与初始值
1. 声明变量格式
[变量修饰字] 变量数据类型 变量名1,变量名2[=变量初值]…;
如:int speed=0;
2. 初始化与初始值
- Java中每个类型都有固定的初始值,如int的初始值是0,具体类型的初始值可以回顾学习数据类型时的内容
- 在类中定义的成员变量可以不用显示初始化为其提供取值即可使用,这时候成员变量的值为其类型的初始值
实例化
类->对象,在程序中,只能调用对象来执行程序,不能使用类。
1. 声明
类名 引用名 = new 类名( ) ;
如:Bike bike = new Bike();
用new为新建对象开辟内存空间,其中,对象的引用放在 栈 中,对象的属性等存在 堆 中。
2. 对象作用域
Java中,变量作用域由 花括号 的位置决定,所以对对象的引用也是由花括号来决定的。
3. 调用成员属性
对象名.成员名
如:bike.price = 2000.0f;
类方法
1. 声明方法的基本形式
[访问控制][方法修饰] 返回类型 方法名称(参数1,参数2,…) {
…(statements;) //方法体:方法的内容
}
如:
public float getBikePrice(int bikeId){
return price;
}
2. 方法的特点
- 定义方法可以将功能代码进行封装。
- 便于该功能进行复用。
- 方法只有被调用才会被执行。
- 方法的出现提高代码的复用性。
- 方法若没有返回值,则用关键字void表示,那么该方法中的return语句如果在最后一行可以省略不写。
- 方法中可以调用方法,不可以在方法内部定义方法。
- 定义方法时,方法的结果应返回给调用者,交由调用者来处理
3. 返回值
- return
- 可以返回空(void)
- 可以是任何类型
构造方法
- 构造方法就是创建对象的同时,完成新对象的初始化工作。
- 没有返回值,连void都没有。
- 方法名必须和类名相同。
- 不能使用修饰符,包括:static,final,abstract。
1. 默认构造方法
- 无参数
- 空方法体,即不执行任何初始化操作
如:
public Bike(){
}
2. 自定义构造方法
[访问权限修饰符]类名(参数列表){
方法体
}
如:
public Bike(float price){
this.price=price;
}
3. 构造方法可以重载
子类可以重写父类的构造方法
class MyTime { //定义时间类
private int mHour, mMinute, mSecond; //三个成员变量,时、分、秒
public MyTime() { //构造方法重载1
mHour = 0;
mMinute = 0;
mSecond = 0;
}
public MyTime(int mHour) { // 构造方法重载2
mHour = mHour;
mMinute = 0;
mSecond = 0;
}
public MyTime(int hour, int minute) { //构造方法重载3
mHour = hour;
mMinute = minute;
mSecond = 0;
}
public MyTime(int hour, int minute, int second) { //构造方法重载4
mHour = hour;
mMinute = minute;
mSecond = second;
}
public void display() { //显示时间信息的方法
System.out.println(mHour + ":" + mMinute + ":" + mSecond);
}
}
/*测试时间类*/
public class Test
{
/*main方法,程序入口*/
public static void main(String[] args)
{
//分别调用不同的构造方法来初始化时间对象
MyTime t1 = new MyTime(); //调用重载方式1
t1.display();
MyTime t2 = new MyTime(8); //调用重载方式2
t2.display();
MyTime t3 = new MyTime(8, 30); //调用重载方式3
t3.display();
MyTime t4 = new MyTime(8, 30, 30); //调用重载方式4
t4.display();
}
}
/*使用重载构造方法可以使初始化对象的方式灵活机动,大大方便类的使用者。*/
方法重载
重载的定义
public class AbsoluteValue{
/*求绝对值的方法*/
public int abs(int x)
{
return ((x >= 0) ? x : -x);
}
/*main方法,程序入口*/
public static void main(String[] args){
//必须先实例化类的对象,才可以调用到其中的成员方法
AbsoluteValue obj = new AbsoluteValue();
int a = -8, b;
b = obj.abs(a); //调用abs方法求a的绝对值
System.out.println(a + "的绝对值是" + b);
}
}
以上代码可以求整数值的绝对值,如果传入的是浮点数怎么办?
我们可以使用重载。
重载的特征
1. 重载:用于定义一组的方法,这些方法的名称相同,但使用不同的参数列表。Java编译器会根据实际参数自动判断具体调用哪个方法进行重载。
2. 方法重载跟方法的返回值没有任何关系,所以只有返回值不同的方法不能构成重载
3. 只有同一作用域范围内的方法才能构成重载
所以以上方法可以修改为
public class AbsoluteValue{
/*求绝对值的方法*/
public int abs(int x){
return ((x >= 0) ? x : -x);
}
public int abs(float x){
return ((x>=0)?x:-x);
}
/*main方法,程序入口*/
public static void main(String[] args){
//必须先实例化类的对象,才可以调用到其中的成员方法
AbsoluteValue obj = new AbsoluteValue();
int a = -8, b;
b = obj.abs(a); //调用abs方法求a的绝对值
System.out.println(a + "的绝对值是" + b);
float c = -8.0f,d;
d = obj.abs(c);
System.out.println(c + "的绝对值是" + d);
}
}
课堂练习
- 在Java中,对于成员方法
float add(float f1, float f2) {……}
下面选项()是对该成员方法的重载。
a. int add(int n1, int n2) {……}
b. float add(float f) {……}
c. void add(float f1, float f2) {……}
d. void add(float f1, float f2, float x) {……}
e. float add(float f2, float f1) {……}
答案:a,b,d
- 在Java中,下列方法()不能与
int fun(int x) {……}
构成方法重载。
a. int fun(int x, int y) {……}
b. float fun(int x) {……}
c. int fun(float x) {……}
d. int fun(int x, int y, int z) {……}
答案:b
this
既然所有的对象都共用相同的成员方法,那么在不同的对象都调用同一方法时,它是怎么确定要使用哪个对象的数据成员呢?
每个成员方法都有一个隐含的 __ this__ 引用,它总是指向调用它的对象;
关键字 __ this __ 给出用于调用成员方法的对象的地址;
每当调用成员方法时,编译器会向this分配调用该方法的对象的地址;
可以像使用任何引用那样使用 __ this __ 。
/*this示例,代码片段*/
public class Student //定义学生类
{
private String mName; //姓名
private int mAge; //年龄
public Student(String name, int age)
{
//隐式调用,等同于this.mName = name;
mName = name;
//显式调用,等同于mAge = age;
this.mAge = age;
}
……
}
static
静态成员变量
在成员变量前加 static 关键字,可以将其声明为静态成员变量;
如果类中成员变量被定义为静态,那么不论有多少个对象,静态成员变量只有 1份 内存拷贝,即 所有对象共享该成员变量;
静态成员变量的作用域只在类内部,但其生命周期却贯穿整个程序。
/** 静态成员变量示例 **/
class Dog
{
public static int count = 0; //静态成员变量
public Dog() //构造方法
{
count++;
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println("当前狗的数量是:" + Dog.count);
Dog d1 = new Dog();
Dog d2 = new Dog();
System.out.println("当前狗的数量是:" + Dog.count);
}
}
- 静态成员变量和程序同生命周期;
- 在没有实例化对象时,可以通过类名访问静态成员变量;
- 也可以通过对象访问静态成员变量,但不论使用的是哪个对象,访问到的都是同一个变量;
- 静态成员变量在声明时最好初始化,如果不进行初始化,系统会默认初始化为初始值。
静态成员方法
在成员方法前加 static 关键字,可以将其声明为静态成员方法;
静态成员方法只能对类的静态成员变量进行操作;
静态成员方法没有 this引用;
在没有实例化对象时,可以通过类名访问静态成员方法。
/** 静态成员方法示例 */
class Dog {
private static int count = 0; //静态成员变量
public Dog() {
count++;
}
//显示数量的方法,静态成员方法
public static void displayCount() {
System.out.println("当前狗的数量是:" + count);
}
}
public class Test {
public static void main(String[] args) {
//没有实例化对象之前,直接通过类名调用静态成员方法
Dog.displayCount();
Dog d1 = new Dog();
Dog d2 = new Dog();
Dog.displayCount();
}
}
包
为什么会有包
有时候,类和类的名称可能发生冲突;Java提供了把类名空间划分为更容易管理的块的机制,这就是 包 ;
包允许将类组合成较小的单元,类似于文件夹;
有助于避免命名冲突,分属不同包的类即便名称相同也不会引起误会;
能在包与包之间对于类的访问权限提供更有力的约束。
package
package 包名
- 必须放在整个源文件的第一条语句
- 包名必须和文件目录名一致
- 如果还包含下一级子包,也必须和文件目录体系相同
缺省包
- 如果省略了package语句,类将保存在一个缺省的没有名称的包中;
- 尽管缺省包很方便,但对于大型的程序,它是不恰当的;
- 请尽量为自己编写的类定义具体的包。
import关键字导入包
- 如要使用到某个包中的类,就需要使用 import 关键字将包或类显式地包括到程序中。
- 一个程序中允许有多条 import 语句,导入多个包或多个类
作业
- 编写一个游戏角色类,有姓名、生命值、魔法值、力量值属性。编写该角色的构造方法。封装其所有属性。并编写其攻击方法。攻击伤害等于其力量值的两倍加10。同时其魔法值会受到和攻击值相同的消耗。
在main方法值中新建两个英雄角色,维恩(生命:480,魔法:200,力量:55)。伊泽瑞尔(生命:450,魔法:300,力量:60)。并模仿伊泽瑞尔攻击了维恩。 - 请为你的同学创建一个Student类,根据其特点,归纳其属性和方法,并实例他/他。请注意好封装。
- 在JAVA中定义一个类,在该类中有一系列的求绝对值的方法。要求使用方法重载。
- 编写一个包含名为Calculator类的程序。定义两个整型属性以及对该两个变量的setter和getter,编写用于对两个属性执行加、减、乘、除运算方法。在main方法里创建该类的对象并访问这些方法。
- 编写一个名为Box的类,含整型的length,width, height,volume四个属性,要求在构造方法中将其初始化,并定义一个计算体积的calcVolume方法和一个输出体积的print方法,在main方法中进行调用。