目录
1.类与对象
面向对象:把具体事物抽象为一个个对象。每一个对象都有自己的状态和行为。对于程序设计来说,状态用变量来表示,行为用方法来表示。对象就是由数据(变量)和相关方法组成的软件包。变量构成对象的核心,相关的方法把变量包围起来与外界隔离。
类:有共同状态和行为的许多对象称为一类。
原型:类中定义各对象共有的变量和方法,称为原型。
实例:由原型可以定义一个个具体的对象,称为实例。对象是类的实例。
子类(导出类) :用继承方法得到的新类。子类继承超类的状态和方法,并且可以重写所继承的方法,使其增加新的用途。
超类(基类):原类对子类而言成为超类。
2.类的定义
class declaration{ //类声明部分
class body //类主体部分
}
2.1.类声明部分
[modifiers] class ClassName [extends SuperClassName] [implements InterfaceNames]
2.1.1.modifiers
modifiers是修饰符,可以设置为abstract,final,public。
1、若用abstract修饰class,表明本类是抽象类, 不能直接实例化为对象。抽象类中存在抽象方法(即未完成的方法),没有方法体,不能直接调用。这种类只能被子类继承,抽象方法由子类重写,并给出完整的方法体。
2、若用final修饰class,表明本类是最终类,不能再被继承,类中方法不能再被重写,保证该类的唯一性。
3、若用public修饰class,表明本类是公用类,可以被当前所属包之外的其他的类和对象调用。在一个Java编译单元中可以有多个类,但只能有一个类声明为public类。
4、若无修饰符,则表明本类不属于以上三种类型,是“友好的”,只能在当前包中使用。
2.1.2.extends部分
SuperClassName是超类名,声明格式为:
class ClassName extends Mysuperclass{
……
}
Java的每一个类都必须有一个超类,若extends部分省略,则其隐含超类为Object,它是Java继承树中的最高类。Object中定义了所有对象必须具有的基本状态和行为。
2.1.3.implements部分
若类声明的implements关键字后给出多个接口名,表明该类实现了所有这些接口,即这些接口中所描述的全部方法都在本类中得到了实现。若省略,则表明该类不使用任何接口。声明格式如下:
class Myclass2 implement Myinterface1,Myinterface2{
……
}
2.2.类主体部分
类体部分包含了类中支持的成员变量和方法的声明。
成员变量:指与一个类或对象相关的变量。在类体中但不在方法体中声明,其作用域是整个类。
类的成员变量代表了类的状态,其方法实现了类的行为。
2.2.1.成员变量
成员变量也可以称为域,可以分为类变量和实例变量。
类变量:在类中只出现一次,系统仅为类变量分配一次内存,前面有关键字static。
实例变量:出现类的每一个实例中,每创建一次新实例,系统都要为实例变量分配内存。
声明一个成员变量的一般格式为:
[accessSpecifier] [static] [final] [transient] [volatile] type variablename
1、accessSpecifier部分
accessSpecifier是访问限制符,限制哪些类可以访问本类的成员变量。
Java为变量提供了4种级别的访问:private,protect,public,friendly。
public:允许所有的类访问。
protected:允许声明它的类、子类以及同一个包中的各类访问。
省略:允许声明它的类以及同一个包中的各类访问。
private:允许该类的实例对象访问。
限制符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
省略 | Y | Y | N | N |
private | Y | N | N | N |
2、static关键字
在声明成员变量时加上static关键字,则表明这个变量是类变量而不是实例变量。
如果只需提供一个变量给某个类的所有变量访问,就可以使用类变量。类变量通常用于定义常数。
类变量可以用类名来访问,但实例变量不能用类名来访问,只能由类实例化后得到的对象名来访问。
3、final关键字
如果在声明成员变量时加上final关键字,则表明这个变量是一个常数,变量名用大写字母。
4、transient关键字
如果加上,则表明这个变量不是本对象的永久状态,对象序列化时将不处理该变量。
5、volatile关键字
如果加上,则表明该变量可以被多个并行线程异步地修改。
6、type关键字
type指变量的类型,即bype、int等。
7、variablename部分
指变量名。
2.2.2.方法
方法由方法声明和方法体两部分组成。
方法声明格式为:
[accessSpecifier] [static] [abstract] [final] [native] [synchronized]
return_type method_name ([paramlist]) [throws exceptionsList]
1、accessSpecifier部分是访问限制符,具体和成员变量的声明一样。
2、static关键字声明该方法是类方法,类方法被类的所有对象共享,若省略为实例方法。
3、abstract关键字声明该方法是抽象方法,没有方法体,必须由子类重写。
4、final关键字声明该方法是最终方法,不能被重写。
5、native关键字声明的方法没有方法体,由平台相关的语言来实现方法体。
6、synchronized关键字声明的方法用于控制多个并发线程对共享数据的访问。
7、paramlist是方法的参数,参数不能与方法体里的局部变量同名。
8、throws exceptionsList是方法的异常处理,它列出可能发生的异常类型,提醒方法的调用者做出适当的处理。
方法体部分:
1、方法体中声明的变量为局部变量,其作用范围只在该方法体内。
2、若方法体返回一个对象,则其对象必须是当前类的类型或是其子类的类型;若返回一个接口类型,则其对象必须实现该接口。
3、在方法体中可以使用关键字this,this在方法体中指当前对象的成员,包括成员变量和方法,当前对象指正在调用方法体的对象,如果方法的某个参数与当前对象的某个成员变量同名,则必须用this来指明成员变量,例如:
class getDate{
int op1,op2;
getData(int op1,int op2){
this.op1=op1;
this.op2=op2;
}
}
方法的参数隐藏了类的成员变量,this.op1指成员变量op1,this.op2指成员变量op2。同样可以用this来调用当前对象的某个方法。(若子类方法隐藏了其超类的某个成员变量,可以用super来指这个变量)
2.2.3.构造方法
构造方法是某个方法和声明它的类同名。用于建立本类的一个新对象,并对新对象进行初始化。构造方法会在new一个对象时自动被调用。
注意:构造方法不能声明返回类型;构造方法中只包含初始化对象属性的语句。
应用如下:
class Rect{
protected float widht,height;
public float area;
//构造方法对成员变量初始化
public Rect(float w,float h){
width=w;
height=h;
area=getArea(w,h);
}
public float getArea(float w,float h){
float a;
a=w*h;
return a;
}
}
class MyRect{
public static void main(string[] args){
Rect rect=new Rect(4.0f,6.0f);
//创建类Rect的实例对象rect,并对w,h初始化
system.out.println("The area is:"+rect.area);
//用对象rect访问实例变量area
}
}
在声明构造方法时可以用访问限制符来具体表明哪些对象可以创建本类的实例,private限制符表明没有其他类可以实例化本类,protect限制符表明只有本类的子类可以创建本类的实例,public表示任何类都可以实例化本类。
2.2.4.方法重载
方法重载:用同一个方法名表示一个类中不同行为的几个方法,但这些方法的参数不能完全一致。可以是参数个数不一致,或者参数类型不一致,甚至是参数顺序不一致。例如:
class Point{
int x,y;
Point(int x,int y){ //构造方法
this.x=x;
this.y=y;
}
double distance(int x,int y){
int dx=this.x-x;
int dy=this.y-y;
return Math.sqrt(dx*dx+dy*dy);
}
double distance(Point p){ //方法重载
return distance(p.x,p.y);
}
}
3.对象
java的对象是类的实例,称对象的类为对象的类型。只要没有对象再使用它,java运行系统会自动将它清楚。
对象创建的格式如下:
type odjectName=new constructor();
1、type是对象的类型,指对象的类或接口。
2、objectName是对象名,
即引用对象的变量。3、new运算符实例化一个新的对象。
4、constructor()是构造方法。如果一个类没有定义构造方法,系统会用默认的构造方法来创建这个类的对象。
补充概念:
1、访问 对象的(成员)变量又称为引用。
2、方法调用又称为消息,对接受该信息的对象产生结果。
4.类的继承
4.1.合成
合成:把现有类的对象放入到一个新类中,并给予适当的初始化。初始化的地方可以在定义对象时,或在构造方法内,甚至在要用该对象时。例如:
class Newclass{
A a=new A(); //在定义对象时初始化
B b;
static String s1;
Newclass(){
b=new B(); //在构造方法内初始化
}
public static void main(String[] args){
Newclass n1=new Newclass();
if(null==s1)s1=new String("abc"); //在要用到对象时初始化
System.out.println(s1);
}
}
上例的a和b经过初始化后,就可以使用A类和B类的成员变量和方法。新类拥有A类对象、B类对象和String对象的功能,具有更强的作用。
4.2.方法重写
方法重写是声明某方法的名字和其超类中的方法同名。若子类方法重写了其超类的某个方法,可以用super来调用那个被重写的方法。
class Myclass{ //超类
boolean op1;
void Mymethod(){
op1=true;
}
}
class Mysub extends Myclass{ //子类
boolean op1;
void Mymethod(){ //方法重写
op1=false;
super.Mymethod(); //调用超类的Mymethod()方法
System.out.println(op1); //输出子类op1
System.out.ptintln(super.op1); //输出超类op1
}
}
public static void main(String[] args){ //主类
Mysub sub=new Mysub();
sub.Mymethod();
}
4.3.构造方法继承
在类的继承过程中,子类的构造方法可以用super调用超类的构造方法,其调用语句在方法体的各语句之前。
class Myclass{
int op1;
Myclass(int op2){
op1=op2;
}
}
class Mysub{
int op3;
Mysub(int op4){
super(1);
op3=op4;
}
}
super(1)调用超类的构造方法,并令op2=1。而Mysub(int op4)的调用,则必须用new运算符来调用。
类继承部分示例:
class Point{ //超类
int x,y;
Point(int x,int y){
this.x=x;
this.y=y;
}
double distance(int x,int y){
……;
}
double distance(Point p){ //方法重载
return distance(p.x,p.y);
}
}
class Point3d extends Point{ //子类
int z;
Point3d(int x,int y,int z){
super(x,y); //重点,易混乱
this.z=z;
}
double distance(int x,int y,int z){ //方法重写
……;
}
double distance(Point3d q){
return distance(q.x,q.y,q.z); //子类的x和y都是调用的超类的成员变量
}
}
子类运行时必须先对超类进行初始化。(需调用超类的成员变量)
5.嵌套类
嵌套类:一个类可以在另一个类中定义。嵌套类可以有4种级别的访问权限,而外部类只有public和friendly两种访问权限。使用嵌套类可以提高代码的可读性和可维护性,增强封装性,并增加类之间的逻辑联系。
嵌套类分为静态嵌套类和非静态嵌套类(内部类)两种。
5.1.静态嵌套类
静态嵌套类在外部类定义成员变量的地方定义,class前面要带有static关键字。
静态嵌套类可以定义自己的静态成员,只能访问外部类的静态成员,外部类要访问静态嵌套类只能通过类名。
创建静态嵌套类的对象的格式为:
class Outerclass{
……;
static class StaticNectedclass{
……;
}
public static void main(String[] args){
Outerclass.StaticNectedclass nestedObject=new Outerclass.StaticNectedclass();
}
}
5.2.内部类
内部类同样在外部类定义成员的地方定义,不带static关键字。
内部类不能定义自己的静态成员,可以直接访问外部类的成员变量和方法。
要创建内部类对象,需先创建外部类对象,格式如下:
class Outerclass{
……;
class Innerclass{
……;
}
public static void main(String[] args){
Outerclass outerObject=new Outerclass();
Outerclass.Innerclass innerObject=outerObject.new Innerclass();
}
}
5.2.1.局部内部类
局部内部类不是在外部类定义成员的地方定义,而是在某个方法体中定义。
局部内部类不能在所在方法体外访问,更为隐蔽。
5.2.2.匿名内部类
public class OuterClass{
public Abc abc(){
return new Abc(){
private int x=1;
public int add(){return ++x;}
};
}
6.接口
如果抽象类的方法全是抽象的,则称为接口。接口是java一种重要的复合数据类型,是一组方法的定义和常量的结合。接口仅提供方法的声明,但不像抽象方法那样必须在继承树中的某个类中实现,它为相互没有关系的类的共同行为定义方法原型,然后由这些类分别实现这些行为。
接口适用于以下场合:
1、在无关的类中获得共同点,但无须强迫这些类建立层次关系。
2、所声明的方法有多个类想要实现。
3、了解某对象的编程接口而无须了解该对象的类。
由于java取消了多继承,只有单一继承。为了使一个类能继承多个类的属性,可以用接口来达到这个目的。在接口声明的extends后面可以有多个接口名,即当前接口可以包含这些接口中的所有成员,相当于继承了多个类的属性。
java的接口是数据类型,可以像其他类型一样用在类型可以用的地方,并且像类一样,可以调用不同对象的方法。
6.1.接口声明部分
完整接口声明格式如下:
[public] interface InterfaceName [extends list of SuperInterfaces]{
……
}
extends部分可以包含多个接口名,这些接口都由当前声明的新接口来“扩展”,即继承它们的常量和方法。
6.2.接口体部分
接口体内的方法都隐含声明为public和abstract,常量隐含声明为public、final和static。(常量名字通常用大写)
类中方法声明的有些关键字不能用在接口中,如不能用transient、synchronized和volatile关键字,也不能用private和protect访问限制。
6.3.默认方法
在java8之前,接口中只能有方法的声明,不能包含任何方法的实现,实现接口的类,要重写接口中所有的方法;java8新增了一个接口功能,允许为接口方法定义默认实现,对应的方法称为默认方法。声明默认方法时,前面要加default关键字。如果有类要实现接口,默认方法可以选择重写或不重写。
7.多态
多态是面向对象编程的特色,指一个方法可以有多种行为。当父类的方法被子类重写时,就可以各自产生自己的功能行为,这就是多态程序设计。
使用多态进行程序设计的核心是使用上转,将抽象类声明的对象作为其子类的上转型对象,再通过其调用子类重写的方法。
帮助理解:https://blog.csdn.net/guchenjun789/article/details/81055317
语法规则为:<父类型><引用变量名> = new <子类型>()
abstract class Figure{
abstract int getArea(int w,int h);
}
class Rectangle extends Figure{
int getArea(int w,int h){
……;
}
}
class Triangle extends Figure{
int getArea(int w,int h){
……;
}
}
class Area{
public static void main(String[] args){
Figure[] f=new Figure[2]; //学习
f[0]=new Rectangle(); //上转
f[1]=new Triangle(); //上转
for(Figure fig:f)
System.out,println(fig.getArea(4,5));
}
}
7.1.接口与多态
接口变量:用接口声明的变量。接口变量可以存放 实现该接口的类 的 实例对象。当用这个接口变量调用方法时,它会根据实际存放的类的实例对象来判断具体调用哪个方法。
interface Bike{
public final boolean isPublic=true;
public float Charge(float h);
public String getBikeName();
}
class Mobike implement Bike{
public float Charge(float h){
……;
}
public String getBikeName(){
……;
}
}
class Ofo implement Bike{
public float Charge(float h){
……;
}
public String getBikeName(){
……;
}
}
public class UseBike{
public static void main(String[] args){
Bike[] b=new Bike[2];
b[0]=new Mobike();
b[1]=new Ofo();
for(Bike bik:b){
System.out.println(bik.getBikeName());
System.out.println(bik.Charge(4));
}
}
}
8.泛型
用某个未指定的类型取代具体类型,实际使用时再代入具体类型。
public class Store<T>{
private T t;
public T get(){
return t;
}
}
当使用这个类时,可以用类类型、接口类型和其他引用类型取代T,但不能用基本类型取代。
实例化Store类的语法有两种,如下所示:
Store<String> c1=new Store<String>();
Store<String> c2=new Store<>();
泛型应用示例:
class Store<T>{
private T t;
public void put(T t){
this.t=t;
}
public T get(){
return t;
}
}
public class TestStore{
Store<Integer> i1=new Store<>();
i1.put(new Integer(3)); //简写为i1.put(3);
Integer i2=i1.get();
System.out.println(i2);
Store<String> s1=new Store<>();
s1.put(new String("abc")); //简写为s1.put("abc");
String s2=s1.get();
System.out.println(s2);
}
泛型接口示例:
interface Room<T>{
void find(T t);
}
class RoomImp1<T> implement Room<T>{ //未指定具体的泛型类型
public void find(T t){
System.out.println("你预定的是"+t);
}
}
class RoomImp2<Integer> implement Room<Integer>{ //指定具体的泛型类型
public void find(Integer t){
System.out.println("你的房间号是"+t);
}
}
public class TestRoomImp{
public static void main(String[] args){
RoomImp1<String> r=new RoomImp1<>(); //创建对象时指定具体的类型
r.find("xx酒店");
RoomImp2 r2=new RoomImp2();
r2.find(503);
}
}
泛型方法:定义时把尖括号部分放在方法的返回值前,示例如下:
class Gen{
public<T> void show(T t){
System.out.println("T:"+t.getClass().getName());
}
}
public class TestGen{
Gen g=new Gen();
g.show("abc");
g.show(123);
}
//结果
//T:java.lang.String
//T:java.lang.Integer
8.1.限界类型参数
限界类型参数:限定可以取代类型参数的实际类型的范围。以上面的store类为例,如果希望只能用水果类型Fruit及其子类来取代T,可以用extends Fruit加在T后,Fruit是T的上界,如:
public class Store<T extends Fruit>{}
8.2.通配符
泛型中的通配符用问号?表示,代表某种未知类型,有3种用法:
1、无界通配符的形式是<?>,代表任何类型,其上界是Object。
2、限界通配符的形式是<? extends T>,其上界是T。
3、下界通配符的形式是<? super T>,其下界是T,要用T的超类来取代未知类型。
9.基本类型的类封装
java类库中很多方法只接收引用类型的参数,基本数据类型不属于引用类型,无法被接受,故java对8种基本数据类型进行了类的封装设计,形成了对应的封装类。
基本数据类型 | 封装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
为方便封装类与基本数据类型的相互转换,java专门提供了自动装箱和自动拆箱。
int m=5;
Integer n=m; //自动装箱
Integer i=new Integer(20);
int j=i; //自动拆箱
10.包
java以包的形式包含类库,相当于其他编程语言的标准库。
10.1.自定义包
如果希望把自己编写的类与接口放在一个包中,可以用package语句来定义一个包,格式为:package pkgname;
该语句位于java源文件的第一句,指明下面声明的类与接口都位于pkgname包中。
10.2.引入包中的类
如果希望引入已有包中的类与接口,有3种方法:
1、用import语句加包名和类名,格式如下:
import pkgname[.pkgname1···].classname;
例如:import java.applet.Applet;
表示引入java.applet包中的Applet类。
2、用import语句引入某个包中的所有对象,格式为:
import pkgname[.pkgname1···].*;
例如:import java.applet.*;
3、在类名前指明它所在的包,例如:
class Myclass extends java.applet.Applet{···}
等价于
import java.applet.Applet;
class Myclass extends Applet{···}
注意:
java编译器为所有程序自动引入java.lang包,编程时不必引入它。
10.3.完整的java源文件
java源文件又称为编译单元,单独编译,扩展名为.java,文件名与public类的类名一致。 除注释外,该文件包含四个部分,顺序为:
1、package语句部分
2、import语句部分
3、类声明部分
4、接口声明部分