JavaSE
一.对象与类:
- 对象:与自然界中的个体对应,需要有属性和行为。个体的属性对应对象的属性,个体的行为对应于对象的方法。
- 类:为了不用无休止的创建相似对象,我们把对象的一些共性(共有的属性和行为)提取出来,写做一个类。不同对象属性的取值可以不同。
1.类定义
- 成员变量
- 成员方法
public class Demo{ //一个文件只能定义一个public类,同时类名必须与文件名相同。
pubilc static void main(String[] args)
{
Student stu1 = new Student(); //创建对象
}
}
class Student{
int name; //成员变量
int number;
public int getNumber() //成员方法。
{
return number;
}
}
①创建对象
Student stu1 = new Student(); //创建对象
一个对象的对象名,是一个引用变量,存储该对象的地址。
②访问对象属性和行为
stu1.name = "ZS";
int number = stu1.getNumber();
③对象的内存映像
需要使用:栈,堆,方法区
public class Demo{ //一个文件只能定义一个public类,同时类名必须与文件名相同。
pubilc static void main(String[] args)
{
Student stu1 = new Student(); //创建对象
}
}
class Student{
int name; //成员变量
int number;
public int getNumber() //成员方法。
{
return number;
}
}
JVM的细节还不太理解。
大概理解为:当需要new Student()时,JVM并不清除Student()是什么类;JVM进而加载解析Student类到方法区中,即 将.class字节码文件存储到方法区,其中存放有Student类中的方法实现代码所对应的字节码指令。JVM解析之后,在堆中创建出一个Student对象,并创建出对象的成员变量,再赋初值。再在栈中的main栈帧中创建出一个引用变量stud1,并将堆中Student类的地址赋给stud1。
④自定义类加载到JVM方法区:
方法区中的字节码是根据需要来动态加载解析类的,每个类只需要加载解析一次。
⑤相同的类所创建的对象,它们的方法是完全相同的吗?
不是,因为在执行方法时,对象可能会去访问它们的成员变量,因为成员变量的不同,所造成执行的成员方法会出现差异。
⑥从语言层面认识类
对比基本数据类型,类定义就是一个数据类型的定义
不同点:我们自定义的数据类型,jvm不认识。
shift + f6 改所有名字
二.面向对象的“特殊”语法
1.成员变量与局部变量的比较:
- 在类中的定义位置不同
- 在内存中的位置不同
- 初始化值不同
- 生命周期不同
方法参数为引用变量
当需要达到交换两值时,有两种可能的操作方式。
第二种方式并不能达到理想的交换效果。因为交换的过程只是在function的栈帧中进行,并没有真正地交换了main中的d1,d2。在function结束后,temp和d1,d2被回收。
2.类的构造方法 —— 类似与数组的静态初始化
public 类名(参数类型 参数1, 参数类型 参数2, ...) //不需要写void,完全没有返回值
{
....
}
构造方法可以有多个。
在构建对象时,调用的构造方法会自动寻求与已有的构造方法相匹配。
在创建对象的最后一步JVM调用构造方法。
注:
如果不设置构造方法,JVM会默认设置了一个无参数的构造方法。如果设置了任意一个构造方法,JVM就不会使用一个默认的构造方法,此时我们要自己定义一个无参数的构造方法。
3.this的使用。
this:代表对象自身的引用。
this使用场景:
- 在构造方法中:this代表正在构造的对象
- 在方法中:this代表正在调用该方法的对象
- this还能够访问构造方法:但是只能在构造方法中使用,必须在构造方法的第一条语句。(构造方式只在创建对象的最后一步JVM调用,对象创建后构造方法不会再被调用)
public Student()
{
this("未知");
}
public Student(String name)
{
this.name = name;
}
4.static修饰符
- static关键字可以修饰成员变量,也可以修饰成员方法。
- 严格意义上讲,被static修饰的成员变量和成员方法已经不是真正意义上的成员变量和方法,但是习惯上我们仍然称作它们为静态变量和静态方法。
- 一般作为工具方法。因为调用方便。直接 类名.方法名 ()
①共享特征
被static修饰的成员变量被该类的所有对象共享,被单独存储在方法区的字节码文件中,分配内存空间,并赋初值。而不存储在对象中(这是判断是否被static所修饰的依据)。
被static修饰的成员方法,从共享的角度与普通方法没什么区别。
②访问特征
可以通过类名直接访问静态变量和静态方法。如 Student.schoolName。当然也能通过对象名. 的方式访问,但不提倡。
③静态变量和静态方法随着类加载而加载
④优先于对象存在
原因:
由static修饰的变量和方法,在类加载之后就存在在方法区中了。向静态变量分配了内存,并赋了初值。静态变量可以直接通过类名访问,无需先创建对象。成员方法角度,被static修饰的成员方法,在没有对象存在的情况下,也可以直接通过类名调用
⑤那为什么创建对象后成员方法也加载到了方法区,却不能通过类名直接调用呢?
因为成员方法可能会去访问成员变量,保险期间,JVM采取一刀切的方式,禁止了这种行为。
⑥类加载的情况(JVM有6种):
- 类名.静态方法 的方式
- 类名.静态变量 的方式
- new一个对象
- 使用反射计数创建该类或接口的Class对象时
- 初始化某个类的子类,会先触发父类的加载
- java.exe命令来运行某个主类(java 类名)
⑦静态方法中只能调用静态方法和访问静态变量( 这同时解释了为什么main调用的函数修饰符都要写成 public static xx xx{} ):
因为静态方法和变量优先于对象存在(成员变量是存储在对象中的)。该举措能防止对象还没创建的情况下静态方法访问非静态成员变量或非静态成员方法的情况发生。
即 : 静态上下文(静态方法的方法体/静态代码块/…)中,不能访问非静态的成员
but,可以在静态方法中new一个对象,从而使用这个对象的非静态成员。或者创建一个匿名对象,匿名对象只能被访问一次。
new Student().eat(); //匿名对象,只能被访问一次
在非静态方法中可以直接调用静态方法和静态变量。
⑧在静态方法or非静态方法中都不能用static关键字定义变量:
因为方法中定义的变量属于局部变量,是被存储在栈中的。而静态变量应该存在于方法区中,这产生矛盾;从共享的角度理解,静态变量应该被类的所有对象共享,属于整个类,(类变量),同样矛盾。
4.代码块
①局部代码块
声明方式和位置 执行时机
public class Student
{
int i;
public void print()
{
{ //局部代码块声明在方法中。
//随着方法的执行而执行。
int j = 0;
System.out.print(j);
}
System.out.print(i);
}
}
②构造代码块
声明方式和位置 执行时机
声明在类中方法体之外。在创建对象时就会执行。可以赋值成员变量,一般编写在变量定义之后。
执行顺序
(成员变量初始化 —> 构造代码块)(看两者谁在前) —> 构造方法
一般把构造函数中都要输出的语句放在构造代码块中。这样可以减少冗余代码。
创建对象时给成员变量赋值,一共有3个场景:
- 构造方法
- 构造代码块
- 成员变量初始化语句
public class Student{
int i = 1;
{
i = 99; //构造代码块 创建对象输出i值 i = 99;
}
/*
{
i = 99 //这种方法也行。创建对象输出i值 i = 1;
}
int i = 1;
*/
public Student()
{
}
}
③静态代码块
声明方式和位置 执行时机
声明在类中方法体之外。
在加载类时就会执行,只执行一次。
因此一般把只需要执行一次的代码放在静态代码块中。
静态代码块也属于静态上下文,所以无法访问非静态变量和方法。
public class Student{
int i = 1;
static {
... //静态代码块
}
...
}
三.package关键字
1.作用:
package用来声明该类存在于哪个包中。
2.补充:
每个类都存在于一个包中,如果没有package关键字,JVM会自动将其放入一个默认包。
四.import关键字
1.前提知识:
如何识别一个类:包名 + 类名(全类名) ----> 类似于文件的完全路径。
2.调用不同包的类:
①方式一:
import 包名
import cs.kaoyan.onepackage.A;
②方式二:
写出类的全类名
class Student{
public static void main(String[] args)
{
cs.kaoyan.onepackage.A a = new cs.kaoyan.onepackage.A();
}
}
注:
- 如果当前包中存在A类,其他包中也存在A类,在不写出全类名和不import其他包的情况下,创建A类型的对象,默认是本包下的A。如果import了其他包,则是调用那个包的A。
- 如果既要本包下的A类,又要别的包下的A类,则别包下的A类需要写出全类名。
- 类中默认导入了java.lang包。
- import存在智能导入方式。只能导入方式注意两点:不能导入包中的子包的类;需要包中的什么类才会导入什么类,不是将整个包中的类导入。
import java.util.*
// 使用到Scanner时只会导入Scanner类。如果创建了A类变量,JVM会先在本包中寻找A类,而不会在智能导包中寻找A类。
五.面向对象和面向过程
1.面向过程:
程序是一个操纵序列“动词”的集合。
算法 + 数据结构
函数是程序的基本单位
2.面向对象:
对象+消息
消息是像对象发出某种消息,对象调用相应方法。
类(class)是程序的基本单位。