面向对象2
1.认识成员函数
成员变量:类定义了对象中所具有的变量,这些变量称作成员变量;(每个变量都有自己的变量,和同一个类的其他对象的分开的)
函数与成员变量:在函数中可以直接写成员变量的名字来访问成员变量
定义和使用成员函数
最简单的成员函数的格式如下:
void 函数名称(){
函数内容;
}
调用方法为“对象名.函数名();”
注意:(1)在类的内部,普通的成员函数可以直接使用同一个类中的成员变量,不需要加对象名,例如“System.out.println("name="+name);”
(2)从原理上讲,当程序执行到“zhangsan .display();”时,程序会跳转到diapaly函数的内部去执行,执行完毕后回到main函数,继续执行main函数中后面的代码。
加入参数的成员函数的格式如下。
void 函数名称(类型1 参数名1, 类型2 参数名2,......, 类型n 参数名n,){
函数内容;
}
调用方法为“对象名.函数名(参数值列表);”
注意:(1)”void init(String n,String s,ine a)“定义了函数init,传入三个参数。这些参数只能在函数内部使用,属于局部变量,其中n,s,a又称为形式参数(简称形参)。
(2)"zhangsan.int("张三",”男“,25);"调用此成员函数,传入3个值给n,s,a,其中"张三",”男“,”25“又称为实际参数(简称实参)。
带返回类型的成员函数 ,格式如下。
返回类型 函数名称(类型1 参数名1, 类型2 参数名2,......, 类型n 参数名n,){
函数内容;
return和函数返回类型一致的某个变量或对象;
}
调用该函数之后,其返回值可以进行下一步使用。如编写一个计算器类,传入一个整数,返回其绝对值。
注意:(1)”int abs(int a)“定义了函数abs,返回一个整数类型的值。
(2)”int result=c.abs(-10);“表示调用该函数,将返回值存入result变量。
(3)如果函数中途遇到return则跳出。
(4)没有返回类型的函数也可以使用 return ,表示跳出该函数,但是不能return一个具体的值。
(5)在有些文献中,成员函数也称为成员方法(Method).成员函数和成员变量等统称为成员。
函数参数的传递
简单数据类型采用值传递
引用数据类型采用引用传递
成员方法
带参数的成员方法 (1)参数是基本数据类型——值传递
(2)参数是引用数据类型——引用传递
值传递,即实参传递给形参:——形参发生变化,与实参无关——8大基本数据类型
引用传递,即实参传递给形参:——形参发生变化,实参跟着一起发生变化——数组,类与对象,接口,字符串等非8大基本数据类型。
this(成员方法(),成员变量)
函数重载
重载:在同一个类中,允许存在一个以上的同名函数,只要他们的参数个数或者参数类型不同即可。比如,如果没有重载,我们再写求和这个方法时,必须写一个对整数的,再写一个
对小数的。这样非常麻烦且不易调用。但有了重载以后,我们可以把对整数和小数的求和整合到一个方法中,不论往里面传的是小数还是整数都可以通过一次调用解决。
特点:与返回值类型无关,只看参数列表(参数的个数,参数的类型,参数的顺序)。
若参数个数不同但类型相同,则重载的代码可以重用,因为重载功能相似。
不能盲目地将函数定义为一样,必须满足以下条件之一:(1)函数参数的个数不同
(2)函数参数的个数相同,类型不同。
(3)函数参数的个数相同,类型相同,但是在参数列表中出现的顺序不同。
注意:(1)函数重载也称静态多态。
(2)多态(Polymorphism)是面向对象编程的特征之一,多态通常来讲就是一个东西在不同情况下呈现不同形态。例如,函数abs在不同参数的情况下可以执行不同的代码,而调用者
只需要记住一个函数名称。
2. 静态变量和静态函数
静态变量
我们用Static表示变量的级别,一个类中的静态变量,不属于类的对象或者实例。因为静态变量与所有的对象实例共享,因此他们不具线程安全性。
通常,静态变量常用final关键来修饰,表示通用资源或可以被所有的对象所使用。如果静态变量未被私有化,可以用“类名.变量名”的方式来使用。
//static variable example
private static int count;
public static String str;
public static final String DB_USER = "myuser"
注意:(1)静态变量可以通过“对象名,变量名”来访问,例如“zhangsan.bankName”,也可以通过“类名,变量名“来访问,例如”Customer.bankName“。一般情况下推荐用”类名,变量名“
的方法访问,而非静态变量是不能用”类名,变量名“的方法来访问。
(2)从底层讲,静态变量在类被载入时创建,只要类存在,静态变量就存在,不管对象是否被实例化。
静态变量的常见应用
1.保存跨对象信息
2.存储对象个数
静态函数
静态函数:函数调用的结果不会访问或者修改任何对象(非static)数据成员,这样的成员声明为静态成员函数比较好。且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通
的全局函数,只不过由于 static 的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。
在静态变量就有静态函数,静态变量和静态函数统称为静态成员。静态函数就是在普通定义前加上关键字static。
静态函数可以通过“类名,函数名”来访问 ,也可以通过“对象名.函数名”来访问,推荐用 “类名,函数名”来访问。
注意
在静态函数调用时对象还没创建,因此在静态函数中不能直接访问类中的非静态成员变量和成员函数,也不能使用关键字this。
静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。
出现在类体之外的函数定义不能制定关键字static。
静态成员函数没有this指针。
Static关键字:
在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份。
用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
静态方法不再是针对于某个对象调用,所以不能访问非静态成员。
可以通过对象引用或类名(不需要实例化)访问静态成员 。
如果某些成员函数只访问静态数据成员,那么最好把他们声明为静态的成员函数,因为这样不需要特定的对象就可以访问这些成员变量了。
静态代码块
①、格式
在java类中(方法中不能存在静态代码块)使用static关键字和{}声明的代码块:
public class CodeBlock {
static{
System.out.println("静态代码块");
}
}
②、执行时机
静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。如果一个类中有多个静态代码块,会按照书写顺序依次执行。后面在比较的时候会通过具体实例来证明。
③、静态代码块的作用
一般情况下,如果有些代码需要在项目启动的时候就执行,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件等资源,我们就可以都放入静态代码块中。
④、静态代码块不能存在任何方法体中
这个应该很好理解,首先我们要明确静态代码块是在类加载的时候就要运行了。我们分情况讨论:
对于普通方法,由于普通方法是通过加载类,然后new出实例化对象,通过对象才能运行这个方法,而静态代码块只需要加载类之后就能运行了。
对于静态方法,在类加载的时候,静态方法也已经加载了,但是我们必须要通过类名或者对象名才能访问,也就是说相比于静态代码块,静态代码块是主动运行的,而静态方法是被动运行的。
不管是哪种方法,我们需要明确静态代码块的存在在类加载的时候就自动运行了,而放在不管是普通方法还是静态方法中,都是不能自动运行的。
⑤、静态代码块不能访问普通变量
这个理解思维同上,普通变量只能通过对象来调用,是不能放在静态代码块中的。
3.使用包
java包的作用是为了区别类名的命名空间
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。、
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,
当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
创建包
创建包的时候,你需要为这个包取一个合适的名字。之后,如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。
包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
将类放在包中
只要在类的定义文件头上加"package 包名;"即可;也可以在Eclipes中快速建立一个包,右击项目中的src目录,选择New----Package命令。
注意:
(1)在源代码中,“package chinasei;”表示该源文件中的所有类都位于包chinasei中。package语句必须放在源代码文件的最前面,也可以不指定package语句,相当于将类放在默认包中,不过指定包,使用更加方便、可靠。
(2)在Java中,推荐包名字的字母小写,例如“chinasei”“bank”等,为了便于阅读,有时候还用“.”隔开,例如“school,admin”“school,stu”等。
(3)在将类放入某个包中之后,包将会用专门的文件夹来表示,例如上面的Customer类,编译出来的.
(4)如果要用命令行来运行某个包中的类,必须首先到达包目录所在的上一级目录,例如本例中的bin目录,使用以下命令。
java包路径,类名
例如,运行school,admin中的Teacher类,首先必须到达bin目录,然后输入以下命令。
java school. admin. Teacher
这样即可运行其中的主函数。
(5)使用命令行编译一个. java文件,在默认情况下不会生成相应目录,例如将前面的Customer. java放在C盘根目录下。
(6)编写一个类,编译成. class文件之后任意放在一个目录下,这并不等于就将该类放在包中。包名必须在源代码中,通过package语句指定,而不是靠目录结构来确定。
访问包中的类
1.在同一个包中直接用类名来访问,不用指定类所在的包。
2.两个类不在同一个包中的情况
注意:
(1)如果一个包中的类很多,可以用“import包名.*”导入该包中的所有类。
(2)在本例中, TeacherTest 类访问Teacher类,必须要保证Teacher是public类(定义时class前必须加关键字public),这将在后面章节讲解。
(3)有时候,包名中有“.”,例如“school. admin”,这并不是说school包中包含了admin包,school. admin仅是一个包名而已。因此,“import school.*;”只是导入了school包中
的类,并没有导入school. admin包中的类,如果要导入school. admin包中的类,必须使用“import school. admin.*;”。
4.使用访问控制修饰符
访问控制修饰符分别是private和public.
类的访问控制修饰符
写与不写关键字public有何区别?
在不写public的情况下属于默认访问修饰,此时该类只能被同一包中的所有类识别。
如果写了public,该类则是一个公共类,可以被包内、包外的所有类识别。
成员的访问控制修饰符
对于成员来说,访问控制修饰符共有4个,分别是private,default、protected,public,示例代码如下。
public class Customer{
private String name;
String sex;
protected int age;
public void display(){}
}
name成员为private类型,sex成员为default类型,age成员为protected类型,display成员为public类型。其中,default类型的成员前面没有任何修饰符。
其特性如下。
( 1) private类型的成员只能在定义它的类的内部被访问。
(2) default类型的成员可以在定义它的类的内部被访问,也可以被这个包中的其他类访问。
(3) protected类型的成员可以在定义它的类的内部被访问,也可以被这个包中的其他类访问,还可以被包外的子类访问。关于子类,将在后面章节讲解。
(4) public类型的成员可以在定义它的类的内部被访问,也可以被包内、包外的所有其他类访问。
很明显,从开放的程度上讲,privateςdefault≤protected<public。
使用类中类
类中类,顾名思义是在类中定义了类,也称为内部类。
为什么要在类中定义类呢?这是由实际需要决定的。例如有两个类A和B,B中要用到A中的一些成员,A又要实例化B,两者的关系错综复杂,此时编写成类中类比较紧凑,示例代码如下。
class Outer{
int a;
void fun0uter (){
Inner inner=new Inner();
}
class Inner{
int b;
void fun(){
a=3;
this.b=5;
}
}
}
注意:
(1)内部类中的成员只在内部类范围内才能使用,外部类不能像使用自己的成员变量一样使用它们。
(2)如果在内部类中使用this,仅代表内部类的对象,因此也只能引用内部类的成员。
5.使用继承
这种策略叫继承( Inheritance )。继承是面向对象的重要特征。因此,在本例中可以将对话框共同的功能写成一个类——Dialog,让两个对话框 FontDialog (“字体”对话框)和 ParagraphDialog
(“段落”对话框)继承它即可。
在Java中,被继承的类称为父类、基类或超类,与之对应的类称为子类或派生类。继承是通过关键字extends实现的,格式如下,
class子类extends父类{}
Jana语言只支持单重继承,除了object类之外每个类都有一个类,object类是所有类的直接父类或间接父类。
如果在定义一个类时没有说明该继承自哪一个类,则该类的父类的父类是object。
特征
(1)继承关系是传递的。若类C继承类B,类B继承类A(多层继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还可以有自己新定义的属性和方法。继承来的属性
和方法尽管是隐式的,但仍是类C的属性和方法。继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。
( 2)继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。
(3)继承提供了软件复用功能。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的重用性。
(4)继承通过增强一致性来减少模块间的接口和界面,大大增加了程序的易维护性。
(5)提供多重继承机制。从理论上说,一个类可以是多个一般类的特殊类,它可以从多个一般类中继承属性与方法,这便是多重继承。Java出于安全性和可靠性的考虑,仅支持单重继承,而通过使用接口机制来实现多重继承。
6.成员的覆盖
方法覆盖(Override)的原则:3同2小1大
3同:
1、同为类方法或同为实例方法
2、方法名相同
3、形参列表相同
2小:
1、子类方法的返回值类型应比父类方法的返回值类型更小或相等
2、子类方法声明抛出的异常应比父类方法声明抛出的异常更小或相等
1大:
子类方法的访问权限应比父类方法的访问权限更大或相等
7.使用多态
我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。 而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。
1.函数传入的形参可以是父类类型,而实际传入的可以是子类对象。
2.函数的返回类型是父类类型,而实际返回的可以是子类对象。
父类和子类对象的类型转换
1.子类类型对象转换成父类类型
根据多态原理,子类对象无须转换就可以赋值给父类引用
2.父类类型对象转换成子类类型
严格来讲,父类类型对象无法转换成子类类型。但是有一种特殊情况,如果父类类型对象原来就是某一种子类类型的对象,则可以转成相应的子类类型对象,此时使用强制转换即可
8.抽象类和接口
含有抽象函数的类称为抽象类,抽象类必须用abstract修饰.
注意
(1)抽象类不能被实例化。例如上面的例子,“Dialog dlg= New Dialog();“是错误的。
(2)抽象函数必须被重写,除非子类也是抽象类。
(3)在抽象类中可以含有普通成员函数。
接口
在抽象类中可以含有普通成员函数,如果一个抽象类中的所有函数都是抽象的,也可以定义为接口(interface)。
在“继承接口”的情况下一般有另一种说法,叫“实现( implements )接口”,子类也称为实现类。
抽象类和抽象方法的联系:如果类中有抽象方法,则此类必须是抽象类;
2)如果是抽象类,可以有抽象方法,也可以没有抽象方法.
3)抽象类不能创建对象继承抽象类的子类,必须重写父类中的抽象方法必须有个子类继承抽家类.
9.其他
关键字final
在Java中有时会遇到关键字final。final的应用如下。
1.用final修饰一个类
该类不能被继承,示例代码如下
final class FontDialog ()
2.用final修饰一个函数
该类在被子类继承的情况下,show函数不能被重写,示例代码如下。
class FontDialog {
public final void show();
}
3.用final修饰一个成员变量
该成员变量的值不允许被改变,即不允许重新赋值(哪怕是同一个值),因此一般用关键字final来定义一个常量,示例代码如下。
class Math{
public final double PI=3.145926;
}
在Java中定义一个类时,如果没有用extend明确标明直接父类,那么该类默认继承Object类,因此Object类是所有类的父类,或者说Java中的任何一个类都是Object的子类。
在Object常用toString和equals两个方法。