类与对象
面向对象
封装
面向对象编程核心思想之一就是将数据和对数据的操作封装在一起。通过抽象从具体的实例中抽取共同的性质形成一般的概念,比如类的概念。
人们经常谈到的机动车类就是从具体的实例中抽取共同的属性和功能形成的一个概念,那么一个具体的轿车就是机动车类的一个实例,即对象。
一个对象将自己的数据和对这些数据的操作合理有效地封装在一起,例如,每辆轿车调用“加速”、“减速”改变的都是自己的运行速度。
继承
继承体现了一种先进的承接历史的编程模式。子类可以继承父类的属性和功能,即继承了父类所具有的数据和对数据的操作,同时又可以增添子类独有的数据和对数据的操作。
多态
多态是面向对象编程的又一重要特征。
有两种意义的多态。
一种是操作名称的多态,即有多个操作具有相同的名字,但这些操作所接收的参数类型必须不同。
另一种多态是和继承有关的多态,是指同一个操作被不同类型对象调用时可能产生不同的行为。
类的定义
类的定义语法格式如下:
[类的修饰符] class 类名 [extends 父类名]
{ …… //类体 }
1.类的修饰符:定义了类间的访问特性。
2.extends:表示所声明的类继承的父类。
若没有extends声明部分,表示所声明的类是从java的根类Object进行继承(默认情况)。
例:public class Circle extends object{
……
}
3.类体:声明类的成员,其中包括成员变量、成员方法和构造函数。
class Vehicle{
int speed; //成员变量定义
float weight,height; //成员变量定义
public Vehicle(){ //类的构造函数
}
void changSpeed(int newSpeed){ //成员方法定义
speed=newSpeed;
}
float getWeight(){ //成员方法定义
return weight;
}
float getHeight(){ //成员方法定义
return height;
}
}
成员变量
成员变量(域)
一个类的数据属性由它的成员变量(域)定义。在类中声明一个域的形式为:
[成员变量修饰符] 类型 成员变量名;
成员变量修饰符包括public,private, protected,package(默认),static和final等。
什么是package权限?
就是同一个包内的各个类都可以访问,而包以外的类就无法访问该变量。
static
static修饰符是干嘛的?
一句话描述就是:方便在没有创建对象的情况下进行调用(方法/变量)。
一个类的各个对象所分别拥有( 称为实例变量)。
还是属于一个类的所有对象共享(称为类变量)。
类变量要以关键字static声明, 这种类变量也可称为静态变量,相应的static修饰的成员方法则称为静态方法,它们统称为类的静态成员。
//例如,下述Student类中,name是实例变量,而count是类变量。
public class Student{
String name;
static int count; //被所有对象共享
}
类变量是与类相关联的数据变量,也就是说,类变量是和该类所创建的所有对象都相关联的变量。
改变其中一个对象的这个类变量就同时改变了其它对象的这个类变量。
因此,类变量的访问不仅可以通过某个对象访问也可以直接通过类名来访问。
类的静态成员的使用格式一般为:
对象.静态变量名;
类名.静态变量名;
对象.静态方法名();
类名.静态方法名();
class Main{
public static void main(String [] args){
System.out.println(A.a); // 0
System.out.println(A.b); // 报错
}
}
class A{
static int a = 0;
int b = 0;
}
class Main{
public static void main(String [] args){
System.out.println(A.a);
A a = new A();
a.a = 15;
System.out.println(a.a + " " + A.a);
}
}
class A{
static int a = 0;
int b = 0;
}
/*
0
15 15
*/
final
final修饰的成员变量只可以被赋值一次,只可以被赋初值,并且在定义的时候必须要赋初值,否则报错。
class Main{
public static void main(String [] args){
A a = new A();
// a.c = 15; // 报错
System.out.println(a.c);
}
}
class A{
final int c = 0;
}
方法
方法一般是对类中的数据成员进行操作。
如果类中的数据成员是private型的,则往往定义一个public的方法来设置数据成员的值或读取数据成员的值。
构造方法
构造函数名和类名是一样的。
构造函数一般用于初始化某个类的对象。
在程序创建Cricle类的对象时,new运算符为该对象分配内存,并调用构造函数来初始化该对象,也就是通过调用Cricle类的构造函数,在构造函数中给对象的各成员变量赋初值。
定义初始化和构造函数的初始化
class Main{
public static void main(String [] args){
A x = new A(5);
System.out.println(x.a);
}
}
class A{
int a = 5;
A(int a) {
this.a += a;
}
}
/*
10
*/
//可以见到该对象的定义的初始化在前。
//就是定义初始化实在构造函数的初始化之前的。
一个类也可以有多个构造方法,(构造方法的重载)在用户不自己定义构造方法,有一个方法区为默认的空的构造方法。
在用户自定义构造方法的时候,会默认的将原来的构造方法进行覆盖。
class Main{
public static void main(String [] args){
A x = new A(1, 2);
A y = new A();
}
}
class A{
int a;
int b;
A (int a, int b) { // 用户自定义的构造方法。
this.a = a;
this.b = b;
}
A () { // 默认的构造方法
}
}
类的作用域
Java中,根据类的作用和相关性,将大量的类进行了分组(包),每组起一个名,称为包名。
同一个包中的类可以互相访问,而不同的包中的类能否互相访问要由类的作用域决定。除了private修饰的类
类的作用域修饰符告诉我们类之间的访问特性。
类的作用域修饰符有两个,要放在class关键字的前面。
这里的default默认就是在类之前不加以任何的修饰的类就是只有包内部的类才可以进行访问。
我们说的可不可以对类进行访问就是可不可以在类中的方法中声明另一个类的对象。
java中对类的注释
java中的JavaDoc注释:
/**
*
*
*
*
*/
这就是可以描述java中类的各个属性方法的注释。
成员访问控制
什么是成员访问控制?
成员访问控制是用来控制当前类中的成员是否可以在其它类中被访问。
如何理解:即在其它类中是否可以通过所创建当前类的对象调用本类的成员,它由成员访问控制修饰符声明。
方法参数传递
①当方法的参数为简单数据类型时,则将实参的值传递给形参;
②当方法的参数为复合数据类型(对象)时,则将实参的值传给形参,此时形参指向与实参相同的堆地址。
Cricle cricle1,cricle2;
cricle1=new Cricle (100);
cricle2=new Cricle (200);
cricle1=circle2;
// 当方法的参数为对象的时候,这里并不只是简简单单的值传递,进行了地址的传递
class Main{
public static void main(String [] args){
A x = new A(1);
B b = new B();
b.print(x);
System.out.println(x.a);
}
}
class A{
int a;
A (int a) {
this.a = a;
}
}
class B{
void print(A a) {
a.a = 12;
System.out.println(a.a);
}
}
/*
12
12
*/
方法重载
Java支持方法的重载,方法的重载定义为在一个类中定义多个同名的方法,方法返回的类型完全相同,不同的是重载的方法参数必须有所区别:
①参数的类型不同。
②参数的顺序不同。这里是指一个方法有多个不同类型参数的情况,改变参数的顺序,也算是一种区分方法。
③参数的个数不同。如下例中的三个重载的方法参数的个数分别是一个、两个和三个。
class Main{
public static void main(String [] args){
A x = new A();
x.f1(10);
x.f1("12");
}
}
class A{
int a;
void f1(int a) {
System.out.println("f1");
}
void f1(String a){
System.out.println("f2");
}
}
// 这里的方法重载符合上述的第一种情况,其余的情况相似于该情况。
this关键字在构造方法中的使用
class Main{
public static void main(String [] args){
A x = new A(5);
System.out.println(x.a);
}
}
class A{
int a = 5;
A(int a) {
this.a += a;
// this.a代表的就是类的属性变量而并不是方法中的局部变量,这里用this加以区分
}
}
java中的垃圾箱
java内存的使用
1.栈内存:用于存放在函数中定义的一些基本类型的变量和对象的引用变量。当超过该变量的作用域时,java会自动释放为该变量分配的内存空间,该内存空间将被另作他用。
2.堆内存:用于存放由new创建的对象和数组。在堆中由new创建的对象和数组是由栈中定义的引用变量来指向的,引用变量的取值为该数组或对象在堆内存中的首地址。引用变量在程序运行到其作用域外后被释放,此时堆中的数组和对象在没有引用变量指向它时,进而变成垃圾。
// 用代码将某个对象变为垃圾
class Main{
public static void main(String [] args) {
A x = new A();
x = null;
}
}
class A{
int a = 5;
}
// 此时x已经成为垃圾,等待回收空间。
垃圾收集器
当一个对象变成垃圾后,垃圾回收器会在其后的某一个时刻启用,回收这些堆内存垃圾所占用的空间,但其启用的时间不由程序员控制,也无规律可循,并不会一产生了垃圾,它就被唤起,甚至有可能到程序终止,它都没有启动的机会。因此这并不是一个很可靠的机制。
我们也可以在任何时候在程序中通过调用System. gc()方法来显式地运行垃圾回收程序。
比如,在创建大量垃圾的代码之后或者在需要大量内存代码之前运行垃圾回收器,来清除那些在内存中不再被引用的对象。
finalize
在一个对象得到垃圾回收之前(无论是显式回收还是自动回收),垃圾收集器给对象一个机会来调用自己的finalize方法,这个过程称为对象的撤销方法。
finalize方法是Object类的一个方法,任何一个对象可以自动通过类的继承使用该方法,在当成垃圾对象被回收之前都会调用这个方法。
类方法和实例方法
一个类中的方法可以互相调用:
实例方法可以调用该类中实例方法或类方法;类方法只能调用该类的类方法,不能调用实例方法;
同时类方法中不可以使用this关键字。
无论是实例变量或类变量,实例方法中均可以操作;而类方法中只能操作类变量不能操作实例变量,也就是说类方法中不能有操作实例变量的语句,
二者为何有着这样的区别呢?
(1)实例方法必须通过对象来调用
(2)类方法可以通过类名调用,此时可能还没有任何对象诞生。
// 如何记录创建了多少个对象
class Main{
public static void main(String [] args) {
A x = new A(0);
A y = new A(0);
A z = new A(0);
A w = new A(0);
System.out.println(A.count);
}
}
class A{
int a;
static int count = 0;
A(int a) {
count ++;
this.a = a;
}
}
/*
4
*/
static代码块
static代码块指的是static{}包裹的代码块,静态代码块中的变量是局部变量,当所在类被加载时执行,且仅执行一次,无论该类实例化多少次
但是当该类没有被实例化的时候该static代码块就一次都不会执行.
class Main{
public static void main(String [] args) {
A x = new A();
A y = new A();
A z = new A();
A w = new A();
}
}
class A{
int a;
static int b = 0;
static {
A.b = 5;
System.out.println(A.b);
}
static {
System.out.println("NO.2");
}
}
/*
5
NO.2
*/
class Main{
public static void main(String [] args) {
}
}
class A{
int a;
static int b = 0;
static {
A.b = 5;
System.out.println(A.b);
}
static {
System.out.println("NO.2");
}
}
//没有任何的输出。
静态代码块可用于初始化类,构造函数用于初始化对象,一个类中可以有多个静态代码块,当一个类中有多个static代码块的时候,按照先后顺序执行。
即使是包含主函数的类,依然先执行静态代码块初始化类,然后执行主函数
static代码块指的是static{}包裹的代码块,静态代码块中的变量是局部变量,当所在类被加载时执行,且仅执行一次,无论该类实例化多少次
静态代码块可用于初始化类,构造函数用于初始化对象,一个类中可以有多个静态代码块
即使是包含主函数的类,依然先执行静态代码块初始化类,然后执行主函数
构造代码块
构造代码块指的是用{}包裹的代码块。构造代码块是给所有对象进行统一初始化,构造代码块中定义的是不同对象共性的初始化内容
对于一个类而言,按照如下顺序执行:
执行静态代码块、执行构造代码块、执行构造函数
对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、构造代码块)>构造函数。
//当一个类的构造方法有多个的时候我们可以使用构造代码快对创建对象的个数进行计数
public class Client {
public static int count = 0;
{
count++;
}
public Client() {
}
public Client(int i) {
this();
}
public Client(String string) {
}
public static void main(String[] args) {
new Client();
new Client(1);
new Client("1");
System.out.println(Client.count);
}
}
使用static的注意事项
使用类的静态方法或静态变量时,注意以下几点:
不能将任何方法体内的局部变量声明为静态。
class Main{
public static void main(String [] args) {
static int a = 5; // 由于main是静态的所以不能执行该语句,编译错误。
}
}
静态方法不能以任何方式引用this和super关键字。
class Main{
public static void main(String [] args) {
}
}
class A{
int a;
static int b = 0;
static {
this.b = 5; // 在static构造函数下使用了this关键字,报错。
}
}
静态方法中只能直接调用同类中其他的静态成员(包括方法和变量),而不能直接访问类中的非静态成员。
class Main{
public static void main(String [] args) {
}
}
class A{
int a;
static int b = 0;
static {
a = 5; // 编译报错
}
}
main()方法是静态的,因此在main()方法中不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类的非静态成员。
枚举类型
枚举(enum )类型,是一种特殊的数据类型,定义了一组预定义的枚举常量列表
使用普通键值对常量,可以限制结果,但无法限制输入变量的范围
而枚举通过预定义的枚举常量,可以限制变量的使用范围
例如,星期,月份,方向,行星等等
class Main{
public static void main(String [] args) {
Season[] a = Season.values();
for(Season i : a) {
}
}
public enum Season{
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
private int code;
Season(int c) {
this.code = c;
}
}
}