Java语言基本元素:类和对象
类是对一类事物的描述,是抽象的、概念上的定义
对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
面向对象程序设计的重点是类的设计
类的设计, 其实就是类的成员的设计
常见的类的成员有:
修饰符 class 类名 {
属性声明;
方法声明;
}
修饰符:
- public 表明该类可以被任意类使用
- 什么也不写 表明该类只能被包内其它类使用
类的正文要用{ }括起来
创建Java自定义类
步骤:
1. 定义类(考虑修饰符、类名)
2. 编写类的属性(考虑修饰符、属性类型、属性名、 初始化值)
3. 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
属性
语法格式:
修饰符 数据类型 属性名 = 初始化值 ;
说明1: 修饰符
常用的权限修饰符有: private、缺省、 protected、 public
其他修饰符: static、 final
说明2:数据类型
任何基本数据类型(如int、 boolean) 或 任何引用数据类型。
说明3:属性名
属于标识符,符合命名规则和规范即可。
成员变量VS局部变量
成员变量 | 局部变量 | |
---|---|---|
声明的位置 | 直接声明在类中 | 方法形参或内部、代码块内、构造器形参或内部等 |
修饰符 | private、 public、 static、 final等 | 不能用权限修饰符修饰(相当于方法的权限 ),可以用final修饰 |
初始化值 | 有默认初始化值 | 没有默认初始化值,必须显式赋值,方可使用 |
内存加载位置 | 堆空间 或 静态域内 | 栈空间 |
方法
什么是方法(method/函数):
方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
将功能封装为方法的目的是,可以实现代码重用,简化代码
Java里的方法不能独立存在,所有的方法必须定义在类里。
方法的声明格式:
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
方法体程序代码
return 返回值;
}
其中:
修饰符: public,缺省,private, protected等
返回值类型:
没有返回值: void(也能用return)。
有返回值,声明出返回值的类型。与方法体中“return 返回值(变量/常量)” 搭配使用
方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开
返回值:方法在执行完毕后返还给调用它的程序的数据。
方法调用:
方法被调用一次,就会执行一次
没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。
定义方法时,方法的结果应该返回给调用者,交由调用者处理。
方法中只能调用方法或属性, 不可以在方法内部定义方法。
return关键字的使用
作用范围:仅仅在方法中
功能:结束方法/结束方法并返回值
注意:return后不能有其他执行语句,因为不可达!
方法重载:
重载的概念:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
重载的特点:
与返回值类型无关,只看参数列表,且参数列表必须不同。 (参数个数或参数类型)。调用时, 根据方法参数列表的不同来区别。
可变个数的形参
JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参
效果等同于数组(但传参方式不同,如果是数组的话只能传数组,但是可变参数可以传一个个该类型的值),不同的是数组作为形参之后仍然能写参数,而可变参数不能
判断重载时可以把可变长度参数看作该类型数组。
//调用可变参数方法与数组参数方法的不同
public static void main(String[] args)
{
//调用数组参数的方法
show(new String[]{"aa", "bb", "cc"});
//调用可变长度形参的方法
show("aa", "bb", "cc");
}
//数组作为形参之后可以跟其他参数
public void show(String[] arr, int num1)
{
for(int i=0;i<arr.length;i++)
System.out.println(arr[i]);
}
//可变长度参数之后不能再有其他参数
public void show(String ...strings)
{
}
//下面两种方法同时写会报错,可变长度参数效果上等同于数组
public void show(String[] arr)
{
for(int i=0;i<arr.length;i++)
System.out.println(arr[i]);
}
public void show(String ...strings)
{
}
说明: 1. 声明格式: 方法名(参数的类型名 …参数名) |
---|
2. 可变参数:方法参数部分指定类型的参数个数是可变多个: 0个, 1个或多个 |
3. 可变个数形参的方法与同名的方法之间,彼此构成重载 |
4. 可变参数方法的使用与方法参数部分使用数组是一致的 |
5. 方法的参数部分有可变形参,需要放在形参声明的最后 |
6. 在一个方法的形参位置,最多只能声明一个可变个数形参 |
参数的值传递机制
方法,必须由其所在类或对象调用才有意义。
Java里方法的参数传递方式只有一种: 值传递。 即将实际参数值的副本
(复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
构造器
构造器的作用: 创建对象;给对象进行初始化
语法格式:
修饰符 类名 (参数列表) {
初始化语句;
}
构造器的特征
它具有与类相同的名称
它不声明返回值类型。(与声明为void不同)
构造器总是伴随new操作一起调用,不能通过类或对象之间调用
不能被static、 final、 synchronized、 abstract、 native修饰,不能有return语句返回值
根据参数不同,构造器可以分为如下两类:
隐式无参构造器(系统默认提供)
显式定义一个或多个构造器(无参、有参)
Java语言中,每个类都至少有一个构造器
默认构造器的修饰符与所属类的修饰符一致
一旦显式定义了构造器, 则系统不再提供默认构造器
一个类可以创建多个重载的构造器
父类的构造器不可被子类继承
构造器重载
构造器重载使得对象的创建更加灵活,方便创建各种不同的对象。
构造器重载,参数列表必须不同
代码块
代码块(或初始化块)的作用:对Java类或对象进行初始化
代码块(或初始化块)的分类:
一个类中代码块若有修饰符, 则只能被static修饰, 称为静态代码块(static block), 没有使用static修饰的, 为非静态代码块。
static{
//静态初始化语句
}
{
//非静态初始化语句
}
静态代码块:用static 修饰的代码块
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
非静态代码块:没有static修饰的代码块
- 可以有输出语句。
- 可以对类的属性、 类的声明进行初始化操作。
- 除了调用非静态的结构外, 还可以调用静态的变量或方法。
- 若有多个非静态的代码块, 那么按照从上到下的顺序依次执行。
- 每次创建对象的时候, 都会执行一次。 且先于构造器执行。
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
内部类一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称(外部类.内部类)。
内部类的类名不能与包含它的外部类类名相同;
分类:类似于变量的分类
- 成员内部类(static成员内部类和非static成员内部类)
4个权限修饰符,abstract,final都能用
static形式的内部类不能调用外部类成员方法或成员变量,但是能调用外部类的类变量和类方法。
非static形式的内部类既能调用外部类成员方法或成员变量,又能调用外部类的类变量和类方法。
创建内部类的实例:
静态的: 外部类.内部类 变量名 = new 外部类.内部类()
非静态的: 外部类.内部类 变量名 = 外部类对象.new 内部类()
非静态内部类调用外部类属性/方法的写法: 外部类.this.属性/方法
静态内部类只能调用外部类的非静态属性/方法
非static的成员内部类中的成员不能声明为static的, 只有在外部类或static的成员内部类中才可声明static成员。 外部类访问成员内部类的成员, 需要“内部类.成员”或“内部类对象.成员”的方式 当想要在外部类的静态成员部分使用内部类时, 可以考虑内部类声明为静态的 编译以后生成OuterClass$InnerClass.class字节码文件
如何声明成员内部类:
class 外部类{
static class 成员内部类{
}
class 成员内部类{
}
}
- 局部内部类(包括方法内,代码块内,构造器内)
不能用权限修饰符和static修饰符,只能用abstract或者final修饰
内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
如何声明局部内部类:
class 外部类{
public 外部类(){ //构造器中
class 局部内部类{
//很少很少见
}
}
方法(){//方法中
class 局部内部类{
//开发中很少见这种,一般都是用匿名内部类
}
}
{//代码块中
class 局部内部类{
//很少很少见
}
}
}
如何使用局部内部类
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
局部内部类的特点
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
局部内部类可以使用外部类的成员,包括私有的。
局部内部类可以使用外部方法的局部变量,但是必须是final的。 由局部内部类和局部变量的声明周期不同所致。
局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
局部内部类不能使用static修饰,因此也不能包含静态成员
- 匿名内部类
匿名内部类不能定义任何静态成员、方法和类
只能创建匿名内部类的一个实例
一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
格式:
new 父类构造器(实参列表) | 实现接口()
{
//匿名内部类的实体部分
}
匿名内部类的特点
匿名内部类必须继承父类或实现接口
匿名内部类只能有一个对象
匿名内部类对象只能使用多态形式引用
对象的创建和使用
创建对象语法: 类名 对象名 = new 类名();
使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)
类的访问机制:
在一个类中的访问机制: 类中的方法可以直接访问类中的成员变量。
(例外: static方法访问非static, 编译不通过。 )
在不同类中的访问机制: 先创建要访问类的对象, 再用对象访问中定义的成员。
匿名对象
我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
如:new Person().shout();
何时使用
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名象。
我们经常将匿名对象作为实参传递给一个方法调用。
内存解析
堆( Heap) , 此内存区域的唯一目的就是存放对象实例, 几乎所有的对象实例都在这里分配内存。 这一点在
Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
通常所说的栈( Stack) , 是指虚拟机
栈。 虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型( boolean、 byte、
char 、 short 、 int 、 float 、 long 、double) 、 对象引用( reference类型,它不等同于对象本身, 是对象在堆内存的首地址) 。 方法执行完, 自动释放。
方法区(Method Area),用于存储已被虚拟机加载的类信息、 常量、 静态变量、 即时编译器编译后的代码等数据