一、类与对象
1.对象(万事万物皆对象):
对象就是真实世界中的实体,对象与实体是一一对应的,也就是说现实世界中的每一个实体都是一个对象,它是一种具体的概念。
2.类:
类是具备某些共同特征的实体的集合,它是一种抽象的概念,用程序设计的语言来说,类是一种抽象的数据类型,,它是对所具有相同特征实体的抽象。
3.类与对象:
类有继承、数据隐藏和多态三种主要特征。利用类的三种特性可以更好的表现现实世界中的事物。类是同一类对象实例的共性的抽象,对象是类的实例化;类是静态的,对象是动态的,对象可以看作是运行中的类。类负责产生对象,可以将类当成生产对象的工厂。
类是对具有共性事物的抽象描述,是在概念上的一个定义.
对象,也叫实例,也就是说一个类的具体化,就是对象或实例
OOP(面向对象的编程)-----Java就是一个纯面向对象的语言
Oriented Object Programming
二、面向对象
按现实生活中的业务将程序代码一个个组织和编写,从而能够让计算机系统识别和理解,这样就可以把现实生活中的业务对象映射到计算机系统中。
1.面向对象的三大特性:封装,继承,多态【单继承多实现】
1)封装:【隐藏内部细节,公开访问方法】
a 封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。例如:将属性使用private关键子封装,对外提供get/set方法进行操作。
b 为实现软件部件的“高内聚”“低耦合”,从而把对象的属性和行为的代码封装到一个“模块”中。用自己的方法进行访问,对外界提供get和set方法。
2)继承
把已经存在的类的内容作为自己的内容,即子类自动共性父类数据和方法的机制,提高了软件的可重用性和可扩展性。
3)多态
a .概念:因为引用变量所指向的具体类型和发出的方法调用在程序运行期间才确定,所以在不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
b.体现:方法的重载与重写。
2.1.重载【OverLoad】
1)方法重载只能出现在同一个类中;
2)发生重载方法名称必须相同;
3)参数满足重载条件(参数个数,参数顺序,参数类型)至少一个不相同;
4)发生重载与修饰符,返回值类型无关。
2.2.重写(覆盖)【 OverRide 】
1) 覆盖只能出现在子类中,如果没有继承关系,不存在覆盖,只存在重载。
2)在子类中被覆盖的方法,必须和父类中的方法完全一样,也就是方法名,返回类型、参数列表,完全一样
l 子类方法的访问权限不能小于父类方法的访问权限
l 子类方法不能抛出比父类方法更多的异常,但可以抛出父类方法异常的子异常
l 父类的静态方法不能被子类覆盖
l 父类的私有方法不能覆盖
l 覆盖是针对成员方法,而非属性
l final修饰的变量必须显示初始化
l 构造方法不能被final修饰
l 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
l 会影响JAVA类的初始化:final定义的静态常量调用时不会执行java的类初始化方法,也就是说不会执行static代码块等相关语句,这是由java虚拟机规定的。我们不需要了解的很深,有个概念就可以了。
a.final关键字在Java中被称为完结器,表示最终的意思。
b.final能声明类、方法、属性。
c.使用final声明的:类不能被继承,方法不能被重写,变量变成常量使其不可以被修改。
d.final修饰的变量一定要初始化值
c.对象的多态性:向上转型:程序会自动完成 父类父类对象=子类实例
向下转型:强制类型转换 子类子类对象=(子类)父类实例
2.在java中如何定义类
具体格式:
类的修饰符 class 类名 extends 父对象名称 implements 接口名称{
类体:属性和方法组成
}
3.在java中定义方法
1)、方法初步
方法是可以重复调用的代码块,通常为了实现各种功能
方法的定义格式:
[方法修饰列表] 返回值类型方法名(方法参数列表){
方法体
}
l 方法修饰列表
是可选项,方法的修饰符可以包括:public,protected,private,abstract,static, final,synchronized,其中public,protected,private不能同时存在
l 返回值类型
如果没有返回值使用void关键字,如果存在返回值可以是基本类型和引用类型,
如果存在返回值,使用return语句。Return语句后面不能再执行语句,因为不可能会执行到,编译器会发生错误。
l 方法名
任意合法的标识符
l 方法参数列表
参数列表可以多个,如:method1(int a, int b),多个采用逗号分割
2)、普通方法实例
代码示例】,存在返回值
public class MethodTest01 {
public static void main(String[] args) { String s = method1(1); System.out.println(s); }
public static String method1(int c) { String retValue= ""; switch(c) { case 1: //System.out.println("优秀"); retValue = "优"; break; case 2: //System.out.println("良好"); retValue = "良好"; break; case 3: //System.out.println("一般"); retValue = "一般"; break; default: //System.out.println("很差"); retValue = "很差"; } return retValue; } } |
【代码示例】,没有返回值
public class MethodTest02 {
public static void main(String[] args) { method1(1); }
public static void method1(int c) {
switch(c) { case 1: System.out.println("优秀"); break; case 2: System.out.println("良好"); break; case 3: System.out.println("一般"); break; default: System.out.println("很差"); } } } |
三、方法的重载(Overload)
重载的条件
n 方法名相同
n 方法的参数类型,个数,顺序至少有一个不同
n 方法的返回类型可以不同(不依靠返回类型来区分重载)
n 方法的修饰符可以不同,因为方法重载和修饰符没有任何关系
n 方法重载只出现在同一个类中
【代码示例】
public class OverloadTest01 {
public static void main(String[] args) { int retInt = sumInt(10, 20); System.out.println(retInt); float retFloat = sumFloat(1.5f, 2.5f); System.out.println(retFloat); double retDouble = sumDouble(2.2, 3.2); System.out.println(retDouble); }
//对int求和 public static int sumInt(int v1, int v2) { return v1+v2; }
//对float求和 public static float sumFloat(float v1, float v2) { return v1+v2; }
//对double求和 public static double sumDouble(double v1, double v2) { return v1+v2; } } |
【代码示例】,采用重载改善以上代码,重载会使我们的编程风格会更好
public class OverloadTest02 {
public static void main(String[] args) { int retInt = sum(10, 20); System.out.println(retInt); float retFloat = sum(1.5f, 2.5f); System.out.println(retFloat); double retDouble = sum(2.2, 3.2); System.out.println(retDouble); }
//对int求和 public static int sum(int v1, int v2) { return v1+v2; }
//对float求和 public static float sum(float v1, float v2) { return v1+v2; }
//对double求和 public static double sum(double v1, double v2) { return v1+v2; }
//正确 public static double sum() { return 0L; }
//错误,重载不依赖返回值 //public static void sum() { // return 0L; //}
//正确 public static double sum(double v1, double v2, int v3) { return 0L; }
//正确 public static double sum(int v3, double v1, double v2) { return 0L; }
//正确 public static double sum(double v1, int v3, double v2) { return 0L; }
//不正确 //public static double sum(double v2, double v1) { // return 0L; //}
} |
4.set get 方法
set : 通过局部变量为全局变量赋值(public + void + 方法名称 + 参数类型 【 依据全局变量类型定义 】)
get : 获取全局变量的值 ( public + 返回值类型【 依据全局变量类型定义 】 + 方法名称 + 参数类型 【 无参数 】 )
5.构造函数(构造方法)
构造方法主要用来创建类的实例化对象,可以完成创建实例化对象的初始化工作,格声明式:
构造方法修饰词列表类名(方法参数列表)
构造方法修饰词列表:public、proteced、private
类的构造方法和普通方法一样可以进行重载
l 构造方法名称必须与类名一致
l 构造方法不具有任何返回值类型,即没有返回值,关键字void也不能加入,加入后就不是构造方法了,就成了普通的方法了
l 任何类都有构造方法,如果没有显示的定义,则系统会为该类定义一个默认的构造器,这个构造器不含任何参数,如果显示的定义了构造器,系统就不会创建默认的不含参数的构造器了。
6. java访问级别修饰符
修饰符 |
类的内部 |
同一个包里 |
子类 |
任何地方 |
private |
Y |
N |
N |
N |
protected |
Y |
Y |
Y |
N |
public |
Y |
Y |
Y |
Y |
default |
Y |
Y |
N |
N |
7.包与import
<1>包其实就是目录,特别是项目比较大,java文件特别多的情况下,我们应该分目录管理,在java中称为分包管理,包名称通常采用小写
<2>采用import引入需要使用的类
//import com.bjpowernode.exam.model.User;
可以采用 * 通配符引入包下的所有类
//此种方式不明确,但简单
import com.bjpowernode.exam.model.*;
//package必须放到所有语句的第一行,注释除外
8、常用关键字
1)static关键字
static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一。下面就先讲述一下static关键字的用法和平常容易误解的地方,最后列举了一些面试笔试中常见的关于static的考题。以下是本文的目录大纲:
一.static关键字的用途
二.static关键字的误区
三.常见的笔试面试题
一.static关键字的用途
在《Java编程思想》P86页有这样一段话:
“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:
方便在没有创建对象的情况下来进行调用(方法/变量)。
2)static关键字(静态)
static修饰符可以修饰:变量、方法和代码块
n 用static修饰的变量和方法,可以采用类名直接访问
n 用static声明的代码块为静态代码块,JVM第一次使用类的时候,会执行静态代码块中的内容(最先执行,而且只能够执行一次)
补充:非静态方法可以直接调用静态方法,但是不能够被静态方法调
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
a、static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:
在上面的代码中,由于print2方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在main方法中有下面一条语句:
MyObject.print2();
此时对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。
而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。
因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
另外记住,即使没有显示地声明为static,类的构造器实际上也是静态方法。
b、static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
c、static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。下面看个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Person{ private Date birthDate; public Person(Date birthDate) { this .birthDate = birthDate; } boolean isBornBoomer() { Date startDate = Date.valueOf( "1946" ); Date endDate = Date.valueOf( "1964" ); return
birthDate.compareTo(startDate)>= 0 && birthDate.compareTo(endDate) <
0 ; } } |
isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Person{ private Date birthDate; private static
Date startDate,endDate; static { startDate = Date.valueOf( "1946" ); endDate = Date.valueOf( "1964" ); } public Person(Date birthDate) { this .birthDate = birthDate; } boolean isBornBoomer() { return
birthDate.compareTo(startDate)>= 0 && birthDate.compareTo(endDate) <
0 ; } } |
因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
二.static关键字的误区
1.static关键字会改变类中成员的访问权限吗?
有些初学的朋友会将java中的static与C/C++中的static关键字的功能混淆了。在这里只需要记住一点:与C/C++中的static不同,Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。看下面的例子就明白了:
提示错误"Person.age 不可视",这说明static关键字并不会改变变量和方法的访问权限。
2.能通过this访问静态成员变量吗?
虽然对于静态方法来说没有this,那么在非静态方法中能够通过this访问静态成员变量吗?先看下面的一个例子,这段代码输出的结果是什么?
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Main { static int
value = 33 ; public static
void main(String[] args) throws Exception{ new Main().printValue(); } private void
printValue(){ int value =
3 ; System.out.println( this .value); } } |
33
这里面主要考察队this和static的理解。this代表什么?this代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,所以输出结果是33。在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。
3.static能作用于局部变量么?
在C/C++中static是可以作用域局部变量的,但是在Java中切记:static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。
三.常见的笔试面试题
下面列举一些面试笔试中经常遇到的关于static关键字的题目,仅供参考,如有补充欢迎下方留言。
1.下面这段代码的输出结果是什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test
extends Base{ static { System.out.println( "test static" ); } public Test(){ System.out.println( "test constructor" ); } public static
void main(String[] args) { new Test(); } } class Base{ static { System.out.println( "base static" ); } public Base(){ System.out.println( "base constructor" ); } } |

base statictest staticbase constructortest constructor
至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
2.这段代码的输出结果是什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public class Test { Person person = new
Person( "Test" ); static { System.out.println( "test static" ); } public Test() { System.out.println( "test constructor" ); } public static
void main(String[] args) { new MyClass(); } } class Person{ static { System.out.println( "person static" ); } public Person(String str) { System.out.println( "person " +str); } } class MyClass extends
Test { Person person = new
Person( "MyClass" ); static { System.out.println( "myclass static" ); } public MyClass() { System.out.println( "myclass constructor" ); } } |
类似地,我们还是来想一下这段代码的具体执行过程。首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。
3.这段代码的输出结果是什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Test { static { System.out.println( "test static 1" ); } public static
void main(String[] args) { } static { System.out.println( "test static 2" ); } } |

test static 1test static 2
虽然在main方法中没有任何语句,但是还是会输出,原因上面已经讲述过了。另外,static块可以出现类中的任何地方(只要不是方法内部,记住,任何方法内部都不行),并且执行是按照static块的顺序执行的。
2)this关键字
this关键字指的是当前调用的对象
this关键字可以使用在:
n 当局部变量和成员变量重名的时候可以使用this指定调用成员变量
n 通过this调用另一个构造方法(一般基本用不到)
需要注意:this只能用在构造函数和成员方法内部,还可以应用在成员变量的声明上,static标识的方法里是不能使用this的(this与static不能够同时使用)