前言
java是一门面向对象的语言,而对象是类的一个实例,有行为和状态。类是一个模板,它描述一类对象的行为和状态。所以本文将从一个类作为模板的角度,从结构上对类这个抽象概念进行分析描述。
模板图
说明:图中标红的属于类这个概念,由于匿名内部类,比较特殊(它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,就可以采用局部内部类来定义它)所以在模板图中就不做展示,关于抽象类会在抽象方法中做说明。
1.成员变量
1.1常量
常量是指在程序的整个运行过程中值保持不变的量,常量值又称为字面常量,它是通过数据直接表示的。常量不同于常量值,它可以在程序中用符号来代替常量值使用,因此在使用前必须先定义。常量与变量类似也需要初始化,即在声明常量的同时要赋予一个初始值。常量一旦初始化就不可以被修改。
它的声明格式为:
final dataType variableName = value;
其中,final 是定义常量的关键字,dataType 指明常量的数据类型,variableName 是变量的名称,value 是初始值.,例如:
final int i =5;
1.2静态常量
由final和static共同修饰的为静态常量。例如:
final static int i=6;
静态常量和常量的区别:
static+final
- 静态常量,编译期常量,编译时就确定值。
- 放于方法区中的静态常量池。
- 在编译阶段存入调用类的常量池中
- 如果调用此常量的类不是定义常量的类,那么不会初始化定义常量的类,因为在编译阶段通过常量传播优化,已经将常量存到调用类的常量池中了
final
- 常量,类加载时确定或者更靠后。
- 当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值
- 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
- 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是它指向的对象的内容是可变的
1.3.普通变量
在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下:
type identifier [ = value][, identifier [= value] ...] ;
格式说明:type为Java数据类型。identifier是变量名。可以使用逗号隔开来声明多个同类型变量。如:
class Demo{
int = 5;
}
1.4静态成员变量
静态成员变量:也叫类变量,独立于方法之外的变量,用 static 修饰。
注意:
static修饰的成员变量属于类,不属于某个对象。即:多个对象访问或修改static修饰的成员变量时,其中一个对象将static成员变量进行了修改,其它的对象的static成员变量值跟着改变,即多个对象共享同一个static成员变量。
举例如下:创建狗类对象时,默认给值 为1,之后依次被修改。具体代码及运行结果如下
public class Demo {
public static void main(String[] args) {
//创建对象dog1
Dog dog1 = new Dog();
//调用test 方法
dog1.test();
//直接通过类名调用,并修改
Dog.age = 2;
System.out.println("类名调用修改后的age:"+Dog.age);
//通过对象修改
int age = dog1.age;
age = 3;
System.out.println("对象调用修改后的age:"+age);
}
}
//创建狗类
class Dog{
static int age = 1;
public void test(){
System.out.println("狗类中的age:"+age);
}
}
输出结果为:
2.代码块
2.1静态代码块
static代码块指的是static{}
包裹的代码块,且静态代码只执行一次,可以通过Class.forName("classPath")
的方式唤醒代码的static代码块,但是也执行一次。
class Demo{
//属性
static int age;
//静态代码块
//静态信息初始化(预先加载资源)
static {
age = 1;
System.out.println("静态代码块");
}
}
2.2构造代码块
使用{}
包裹的代码区域,这里的代码区域特指位于class{}
下面的而不是存在于其他type method(){}
这类函数下面的代码区域
class Demo{
{
System.out.println("构造代码块");
}
}
3.构造方法
构造方法,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们,即构造函数的重载。
语法规则:
1.方法名必须与类名相同
2.无返回值类型,也不能用void修饰(有任何返回值类型的方法都不是构造方法)
3.可以指定参数,也可以不指定参数;分为有参构造方法和无参构造方法
构造方法的特点:
1.当没有指定构造方法时,系统会自动添加无参的构造方法。
2.构造方法可以重载:方法名相同,但参数不同的多个方法,调用时会自动根据不同的参数选择相应的方法。
3.构造方法是不被继承的
4.当我们手动的指定了构造方法时,无论是有参的还是无参的,系统都将不会再添加无参的构造方法。
例如,创建一个Person 类,添加age,name 属性,并添加无参构造及有参构造
class Person{
//属性
int age;
String name;
//无参构造
public Person() {
}
//一个参数构造
public Person(int age) {
this.age = age;
}
//多个参数的构造
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
4.内部类
4.1成员内部类
首先内部类的概念是:在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
成员内部类:在方法外类内定义类。(具体细节及注意事项等在下面代码中注明)
/**
* 成员内部类
*/
public class InnerDemo2 {
public static void main(String[] args) {
/**
* 方法一
*/
//创建成员内部类对象
Outer2.Inner2 inner2 = new Outer2().in;
//对象调用内部类方法
inner2.n();
/**
* 方法二
*/
Outer2.Inner2 inner21 = new Outer2().new Inner2();
//对象调用内部类方法
inner2.n();
}
}
//外部类
class Outer2{
//属性
static int i =1;
//非静态属性,可以通过对象调用
Inner2 in = new Inner2();
/**
* 成员内部类:可以当成一个大的属性
* 1.可以定义所有的非静态信息(属性,方法)及静态常量
* 2.可以被4个访问权限修饰符修饰及final、abstract
* 3.可以获取外部类所有信息
*/
class Inner2{
int x=2;
static final int xx =3;
//报错 static 不能修饰
//static int xxx =4;
public void n(){
System.out.println(i);
m();
}
}
//方法
public void m(){}
}
4.2静态内部类
静态内部类:成员内部类加上static(具体细节及注意事项等在下面代码中注明)
/**
*静态内部类
*/
public class InnerDemo3 {
public static void main(String[] args) {
//创建静态内部类对象
Outer3.Inner3 inner3=new Outer3.Inner3();
inner3.n();
}
}
//外部类
class Outer3{
//属性
static int i=1;
//静态内部类
//可以定义所有的信息以及静态常量
//可以进行继承和实现
//可以被访问权限修饰符以及final/abstract
//只能获取外部类的所有静态信息
static class Inner3 extends Object implements Cloneable{
static final int x=2;
public void n(){
System.out.println(i);
}
}
//方法
public void m(){}
}
5.成员方法
方法的定义:
- 方法是类或对象的行为特征的抽象。
- Java中的方法不能独立存在,所有的方法必须定义在类中。
- 使用 “类名.方法” 或 “对象.方法” 的形式调用。
- 语法格式:
权限修饰符 返回值类型 方法名(参数类型 参数名) {
// 方法体
// 返回值
}
5.1静态方法
静态方法:static修饰的方法,从属于类。最常见的main()方法就是一个静态方法
public class Demo {
public static void main(String[] args) {
}
}
静态方法随着类的加载而加载到方法区的静态方法区里,与类同级也叫类方法,通过类名.形式来调用。静态方法存放在静态区里不会被赋予系统默认初始值,当静态方法被调用时会加载到栈中进行执行(类名.形式--参考如下代码)。
public class Demo {
public static void main(String[] args) {
//直接通过类名.形式来调用
Dog.eat();
}
}
//创建狗类
class Dog{
static void eat(){
System.out.println("狗吃东西");
}
}
注意事项:
- 静态方法可以重载
- 静态方法不能重写
- 静态信息(变量、方法。。)可以使用静态信息,但是不能直接使用非静态信息
- 非静态信息可以直接使用静态信息以及非静态信息
- this 是非静态的,静态方法里面不能直接使用
5.2普通方法
普通方法:没有static,final 等关键字修饰的方法
- 可以进行方法的重载
- 可以进行方法的重写
//创建狗类
class Dog{
public void sleep(){
System.out.println("狗在睡觉");
}
}
5.3最终方法
最终方法:被 final 修饰的方法
注意事项:
- 最终方法不能被重写
- 最终方法可以重载
- 最终类和非最终类都可以包含最终方法
public class demo {
//编写最终方法add
public final static int add(int a,int b) {
return a+b;
}
}
//此时会报错“cannot override the final method from demo”
//不能重写来自demo的最终方法
public class mydemo extends demo{
public static int add(int a,int b) {
return a+b;
}
public static void main(String[] args)
{
int x=10;
int y=2;
System.out.println(add(x,y));
}
}
//非最终类包含最终方法
class demo {
public final static int add(int a,int b) {
return a+b;
}
public static void main(String[] args)
{
int x=20;
int y=5;
System.out.println(x/y);
System.out.println(add(x,y));
}
}
//运行结果:
//4
//25
5.4抽象方法
抽象方法:被关键字abstract 修饰的方法
当父类中的某个方法被所有子类进行不同程度的重写,那么父类里的这个方法就没有实际意义,则舍弃掉方法体,加上 abstract 变成抽象方法(没有方法体---一定要重写)。
抽象类
抽象方法所在的类就是抽象类。如果普通类继承抽象类,那么需要重写所有的抽象方法,如果不想重写,则类需要修改为抽象类。
注意:
- 抽象类里不一定含有抽象方法
- 抽象类不能创建对象,否则能调用到抽象方法,就会出现问题(可以定义构造方法,但是不能创建对象)
- 抽象类可以做属性初始化
- 抽象方法支持重载(重载只和方法名和参数列表有关)
- 抽象方法不可以被private/final/static,抽象方法一定需要重写
- 抽象类不能被final 修饰,因为抽象方法一定需要重写,重写前提是继承,最终类没有子类就不行
- 抽象类的目的主要是为了延展类继承结构
/**
* 抽象类:Employee
*/
abstract class Employee
{
//属性
private String name;
private String address;
private int number;
//抽象方法
public abstract double computePay();
}
5.5方法内部类
方法内部类:方法内定义的类。
注意:
- 方法内部类中可以定义所有的非静态信息以及静态常量
- 方法内部类中可以进行正常的继承和实现
- 方法内部类不能被访问权限修饰符来修饰,但是可以被final、abstrat 修饰
- 方法内部类可以获取外部类所有的信息
- 方法内部类只能获取本方法中的常量
- 方法内部类创建对象需要在本方法中
package com.tedu.inner;
/**
* 方法内部类
*/
public class InnerDemo1 {
public static void main(String[] args) {
//外部类对象调用m()方法,执行创建内部类对象的代码
new Outer1().m();
}
}
//外部类
/**
* 类只能被public default 修饰
*/
class Outer1{
//属性
int x = 1;
//方法
public void m(){
/**
* 1.jdk 1.8 开始默认底层加上final
* 2.jdk1.7 及其以前需要强制加上final
*/
int k = 10;
//此处修改k=8 内部类System.out.println(k); 就会报错
//k=8;
//方法内部类
/**
* 1.可以定义所以非静态属性和方法以及[静态常量]
* 2.可以进行正常的继承和实现
* 3.不能被访问权限修饰符修饰,但是可以被final,abstract 修饰
* 4.方法内部类,可以获取外部类所有的信息
* 5.只能获取本方法中的常量信息
*/
class Inner1 extends Object implements Cloneable{
int y = 2;
//静态属性和方法不行
//静态区没有存储所以
static final int yy=2;
public void mn(){
System.out.println(x);
n();
//只有拿本方法中的变量才会默认加上final,否则不加,比如上面执行k=8时,就
//不会添加final
System.out.println(k);
//报错,k 默认是常量不能被改变
//System.out.println(k=1);
}
}
//在本方法中创建内部类实例
Inner1 inner1 = new Inner1();
inner1.mn();
}
public void n(){}
}