JAVA-类与对象

类与对象
面向过程与面向对象:
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象(OOP)的三大特征:
 封装——把数据隐藏在对象里面,不让外部对其随意操作。
 继承——扩展类的功能。
 多态——方法的重载、对象的多态性

类:
类是组成Java程序的基本元素,它封装了一系列的变量(即数据成员,也称为“域(field)”)和方法(即成员方法 method),是一类对象的原型。创建一个新的类,就是创建一个新的数据类型。实例化一个类,就得到一个对象。因此,对象就是一组变量和相关方法的集合,其中变量表明对象的状态、属性,方法表明对象所具有的行为。
类的定义:
[修饰符]class 类名 [extends 父类名] [implements 接口名表]
{ // 类体
成员变量声明
方法成员声明
}
例、定义一个简单的Person类:
public class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
} }
注意:该类中有两个属性name、age和一个方法tell().类以及定义出来了,但只有类是不能直接使用的,要实例化一个对象才可以使用.
例、实例化一个对象:
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
} }
public class Demo01{
public static void main(String args[]){
Person per = new Person() ; // 产生实例化对象per
} }
对象产生之后,就可以调用类中的一系列操作了。
例、为Person对象中的name和age赋值,并调用tell()方法
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo02{
public static void main(String args[]){
Person per = new Person() ; //*产生实例化对象;如果对象只声明的话,则无法
*直接使用,必须实例化后才可以正确使用。若该语句改为
*Person per则将出现空指向异常(NullPointerException)*/
per.name = "张三" ; // 为名字赋值
per.age = 30 ; // 为年龄赋值
per.tell() ; // 调用方法
}
}
一个类可以产生多个对象。
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo03{
public static void main(String args[]){
Person per1 = null ; // 声明对象
Person per2 = null ; // 声明对象
per1 = new Person() ; // 实例化对象
per2 = new Person();
per1.name = "张三" ; // 为名字赋值
per1.age = 30 ; // 为年龄赋值
per2.name="李四";
per2.age = 33 ;
per1.tell() ; // 调用方法
per2.tell() ;
}
}
其内存划分如下图-1:

图-1
因为声明了两个对象,所以在栈内存空间中开辟了两个空间,保存二个对象,之后些两个对象分别实例化,只要一出现关键字new就表示开辟新的内存空间。那么这二个对象之间不会互相影响
将上例改为:
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo04{
public static void main(String args[]){
Person per1 = null ; // 声明对象
Person per2 = null ; // 声明对象
per1 = new Person() ; // 实例化对象
per2 = per1 ; // 引用传递
per1.name = "张三" ; // 为名字赋值
per1.age = 30 ; // 为年龄赋值
per2.name="李四";
per2.age = 33 ;
per1.tell() ; // 输出:姓名:李四,年龄:33
per2.tell() ; //同样输出:姓名:李四,年龄:33
}
}
其过程如下图-2:

图-2

图-3
构造方法:
在每个类中都存在一个构造方法,构造方法的主要目的是为类中的属性初始化。如果在一个类中没有明确声明一个构造方法的话,则自动生成一个无参的,什么也不做的构造方法。
构造方法的名称必须与类名一致
构造方法定义时没有返回类型说明
不能在构造方法使用return语句
构造方法本身是可以进行重载操作的,重载原则与普通方法一样
如果一个类中已声明了一个构造方法,则不会生成无参什么都不做的构造方法。
例:
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
Person(String name,int age) //声明构造方法
{this.name=name;
this.age=age;
}
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo05{
public static void main(String args[]){
Person per1 = new Person("张三",30);
Person per2 = new Person("李四",33);
per1.tell() ; // 调用方法
per2.tell() ;
}
}

类的方法:
方法是一段可重复调用的代码,其定义格式:
[修饰符] [static] 返回值类型 方法名(类型 参数1,类型 参数2……)
{方法体
}
方法名的命名规范:第一个单词的首字母小写,之后每个单词的首字母大写。


方法的重载:方法名相同,参数类型或个数不同。例:
public class Demo06
{public static int add(int a,int b)
{return a+b;
}
public static int add(int a,int b,int c)
{return a+b+c;
}
public static double add(double a,double b)
{return a+b;
}
public static void main(String[] args)
{int a=1,b=2,c=3;
double d=1.5,e=2.5;
System.out.println(add(a,b)); //输出3
System.out.println(add(a,b,c)); //输出6
System.out.println(add(d,e)); //输出4.0
}
}

使用重载时要注意以下情况:
public class Demo07
{public static int add(int a,int b)
{return a+b;
}
public static float add(int a,int b)
{return a+b;
}
public static void main(String[] args)
{
}
}
运行后将出现以下错误:

该操作不是方法的重载,因为重载的时候,看的不是方法的返回类型,而是参数的类型或个数。
在方法的使用中,可以用return来结束一个方法的操作。
输出0~9的数字
public class Demo08
{
public static void f(int begin, int end)
{
if(begin>end) return; //结束该方法
System.out.println(begin);
f(begin+1, end);
}
public static void main(String[] args)
{
f(0,9);
}
}

方法的递归(方法自己调用自己)
有5个人坐在一起, 问第5 个人几岁,他说比第4个人大2岁。问第4个人岁数,他说比第3 个人大2岁。问第3个人,又说比第2个人大2岁问第2个人,说比第1个人大2岁。最后再问第 1个人,他说是10岁请问第5个人几岁?
public class Demo09
{static int age(int n)
{ int c;
if(n==1) c=10;
else c = age(n-1)+2;
return c ;
}
public static void main(String[] args)
{
System.out.println(age(5));
}
}

类的封装:
“封装”是面向对象思想的第一大要素,封装性是类的重要特性,如果没有能体现"封装性”的类,那么面向对象的另外两大要素”实现类的继承”以及”类的多态”将成为无源之水、无本之木。
public 声明的数据成员和成员函数可从类外部的任何地方访问。
而private 数据将被隐藏,在类外不可见,这就实现了数据封装的思想。
要从类外操纵private 成员,只能通过类的public或protected成员来实现。
看以下例子。


class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo10{
public static void main(String args[]){
Person per = new Person() ; // 实例化对象
per.name = "张三" ; // 为name属性赋值
per.age = 30;
per.tell() ;
}
}
因为现在类中的所有操作都是对外部可见的,可以直接访问。可通过封装性来解决此问题,在JAVA中封装有很多的体现,但最简单的体现就是加入“private”关键字。上例改为:
class Person{
private String name ; // 表示人的姓名
private int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class Demo11{
public static void main(String args[]){
Person per = new Person() ; // 实例化对象
per.name = "张三" ; // 为name属性赋值
per.age = 30;
per.tell() ;
}
}
运行后

name和age属性石使用private关键字声明的,所以无法在外部直接访问。证明现在的属性是安全的,可以直接保护了。但是现在的代码是安全了,知识安全过头了,都无法进行操作了。那该怎么办呢?被封装的属性可通过setter和getter方法设置和取得。如下例:
class Person{
private String name ; // 表示人的姓名
private int age ; // 表示人的年龄
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + this.getName() + ",年龄:" + this.getAge()) ;
}
public void setName(String n){
name = n ;
}
public void setAge(int a){
if(a>=0&&a<=200)
age = a ;
}
public String getName()
{return name ; }
public int getAge()
{return age ;}
}
public class Demo12{
public static void main(String args[]){
Person per = new Person() ; // 实例化对象
per.setName("张三") ; // 为name属性赋值
per.setAge(-30);
per.tell() ;
}
}


类的继承:
通过继承可以简化类的定义,扩展类的功能。
实现继承的方式:class 子类名称 extends 父类{}
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
Person(String name,int age)
{this.name=name;
this.age=age;
}
public void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
class Student extends Person
{String id; //学号
Student(String id,String name,int age)
{super(name,age);
this.id=id;
}
void printId()
{System.out.println("学号:"+id);
}
}
public class Demo13{
public static void main(String args[]){
Student s=new Student("001","张三",20);
s.printId();
s.tell();
}
}
JAVA只支持单继承,不允许多继承,虽然一个父类可以有多个子类,但一个子类只能有一个父类。就如,一个父亲可以有多个孩子,但一个孩子只能有一个亲身父亲。JAVA虽然不允许多继承,但可以多层继承,即:父类—子类—孙类。


继承的规定:子类只继承父类所有的公有成员和公有方法,无法继承私有的属性或方法。
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
Person(String name,int age)
{this.name=name;
this.age=age;
}
private void tell(){ // 定义说话的方法
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
class Student extends Person
{String id; //学号
Student(String id,String name,int age)
{super(name,age);
this.id=id;
}
void printId()
{System.out.println("学号:"+id);
}
}
public class Demo14{
public static void main(String args[]){
Student s=new Student("001","张三",20);
s.printId();
s.tell();
}
}运行如下:



子类对象在实例化时,默认调用父类中无参构造方法。
class Person{
String name ; // 表示人的姓名
int age ; // 表示人的年龄
Person()
{System.out.println("***父类***");}
public void tell() // 定义说话的方法
{System.out.println("姓名:" + name + ",年龄:" + age);
}
}
class Student extends Person
{String id; //学号
Student()
{
System.out.println("***子类***");
}
void printId()
{System.out.println("学号:"+id);
}
}
public class Demo15{
public static void main(String args[])
{new Student();}
}
运行后输出:
***父类***
***子类***
方法的覆写:
方法名称与参数要完全一样,在覆写之后子类调用的方法永远是覆写之后的方法。覆写时子类方法的权限不能比父类拥有更严格的访问权限,覆写之后的权限最好与父类中的保持一致。
class Person{
public void tell()
{System.out.println("***覆写前***");}
}
class Student extends Person
{ public void tell()
{System.out.println("***覆写后***");}
}
public class Demo16{
public static void main(String args[])
{Student s=new Student();
s.tell();}
} //运行后输出:***覆写后***
多态性:
多态从字面去解释就是多种形态...
具体到语言来说,
就是一个父类派生出来的多个子类,
这些子类都继承了父类的共性,
但各自拥有自己的特性,
也就是说子类是父类的多种形态(多态)你可以通过实例化某个子类
来将对象传给父类,
让父类(共性)去完成你所实例化的字类的属性或方法(特性)。
方法的重载与覆写实际上就是属于多态的一种体现。
比如,一个父类:车;有一些子类:奔驰、宝马、欧迪……。定义一个方法fun指明车的品牌,所有子类也都有这个方法fun。
车 a=new 奔驰();
车 b=new 宝马();
车 c=new 欧迪();
a. fun()则可得到奔驰,b.fun()则可得到宝马,c.fun()则可得到欧迪。

对象的多态性主要指的是,子类与父类对象的相互转换关系。
向上转型:父类名 父类对象 =子类实例
向下转型:子类名 子类对象 =(子类名)父类实例
class Car
{public void fun1()
{System.out.println("***汽车品牌***");}
public void fun2()
{System.out.println("***桥车型***");}
}
class Benchi extends Car
{public void fun1() //将父类的方法覆写
{System.out.println("***奔驰***");}
public void fun3() //此方法为子类自己定义的,父类中不存在
{System.out.println("车牌:粤B11223");}
}
public class Demo17
{public static void main(String[] args)
{Car a=new Benchi(); /*发生向上转型:子类——>父类,
*父类中有的方法才可调用。如a.fun3()则会报错,父类中无fun3()方法*/
a.fun1(); //输出:***奔驰***
a.fun2(); //输出:***桥车型***
}
}


如果想调用fun3()的方法则应发生向下转型的关系
class Car
{public void fun1()
{System.out.println("汽车品牌");}
public void fun2()
{System.out.println("桥车型");}
}
class Benchi extends Car
{public void fun1() //将父类的方法覆写
{System.out.println("***奔驰***");}
public void fun3() //此方法为子类自己定义的,父类中不存在
{System.out.println("车牌:粤B11223");}
}
public class Demo18
{public static void main(String[] args)
{Car a=new Benchi(); /*发生向上转型:子类——>父类,此句若改为:
*Car a=new Benchi()则会出现以下异常:
*Exception in thread "main" java.lang.ClassCastException:
*A cannot be cast to B*/
Benchi b=(Benchi)a; //发生向下转型(强制)
b.fun1(); //输出:***奔驰***
b.fun2(); //输出:***桥车型***
b.fun3(); //输出:车牌:粤B11223
}
}

设计一个方法,可以接收Car类的所有子类的实例。
class Car
{public void fun1()
{System.out.println("汽车品牌");}
public void fun2()
{System.out.println("桥车型");}
}
class Benchi extends Car
{public void fun1() //将父类的方法覆写
{System.out.println("***奔驰***");}
public void fun3() //此方法为子类自己定义的,父类中不存在
{System.out.println("车牌:粤B11223");}
}
class Baoma extends Car
{public void fun1()
{System.out.println("***宝马***");}
public void fun4()
{System.out.println("车牌:粤B44556");}
}
public class Demo19
{public static void main(String[] args)
{fun(new Benchi());
fun(new Baoma());
}
public static void fun(Benchi bc)
{ bc.fun1();
bc.fun3();
}
public static void fun(Baoma bm)
{ bm.fun1();
bm.fun4();
}
}
以上方式是通过方法的重载完成的,存在以下缺点。若Car类有10000个子类则须重载10000次。而且在每次增加子类时都须修改代码本身。所以此时用对象的多态性就可以很好的解决此类问题。因为所有的对象都会发生自动的向上转型。
class Car
{public void fun1()
{System.out.println("汽车品牌");}
public void fun2()
{System.out.println("桥车型");}
}
class Benchi extends Car
{public void fun1() //将父类的方法覆写
{System.out.println("***奔驰***");}
public void fun3() //此方法为子类自己定义的,父类中不存在
{System.out.println("车牌:粤B11223");}
}
class Baoma extends Car
{public void fun1()
{System.out.println("***宝马***");}
public void fun4()
{System.out.println("车牌:粤B44556");}
}
public class Demo20
{public static void main(String[] args)
{fun(new Benchi());
fun(new Baoma());
}
public static void fun(Car c)
{c.fun1();}
}
但以上操作依然 存在一些问题,无法调用子类中自己定义的方法(父类不存在的方法)。且各个子类的方法又不尽相同,若要调用谋个子类的方法,则先判断所属那个子类。JAVA中提供了instanceof关键字完成这样的功能。
格式:对象 instanceof 类 // 返回boolean类型的数据,true或false。
class Car
{public void fun1()
{System.out.println("汽车品牌");}
public void fun2()
{System.out.println("桥车型");}
}
class Benchi extends Car
{public void fun1() //将父类的方法覆写
{System.out.println("***奔驰***");}
public void fun3() //此方法为子类自己定义的,父类中不存在
{System.out.println("车牌:粤B11223");}
}
class Baoma extends Car
{public void fun1()
{System.out.println("***宝马***");}
public void fun4()
{System.out.println("车牌:粤B44556");}
}
public class Demo21
{public static void main(String[] args)
{fun(new Benchi());
fun(new Baoma());
}
public static void fun(Car c)
{c.fun1();
if(c instanceof Benchi)
{Benchi bc=(Benchi)c;
bc.fun3();}
if(c instanceof Baoma)
{Baoma bm=(Baoma)c;
bm.fun4();}
}
}
运行后输出:
***奔驰***
车牌:粤B11223
***宝马***
车牌:粤B44556
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值