目录
1.什么是面向过程,什么是面向对象
2.什么是类和对象
3.类的定义和使用
4.成员变量的初始化
5.toString
6.关于static
7.访问限定符
8.代码块
9.内部类
10.类和对象的内存布局
1.什么是面向过程,什么是面向对象
面向过程:要按照业务流程按部就班的来组织代码。
面向对象:要先把业务中的一些概念先提取出来,作为“对象”,然后把对象的每个属性和行为都安排好,然后再去组织业务流程。
2.什么是类和对象
Java中的内置类型不够用,所以根据自己的实际需要创建出一些类型,由自定义的类型创建出来的变量就是对象。类相当于图纸,对象是根据图纸盖出来的房子。
3.类的定义和使用
1)定义示例:
class Cat {
public String name; //姓名
public int age; //年龄
public String gender; //性别
public void eat(){
System.out.println("小猫正在吃");
}
public void sleep(){
System.out.println("小猫正在睡觉");
}
}
class为定义类的关键字,Cat为类的名字,{}中为类的主体。
其中name,age,gender称为成员属性/成员变量,这几个变量信息是对类的描述。
eat(),sleep()称为成员方法,主要说明类有什么功能
注意:
- 类名使用大驼峰
- 一个.java文件可以包含多个类
- 一个.java文件至少得有一个class是public修饰的
- 被public关键字修饰的类名,必须和.java文件的名字相同(大小写敏感)
2)类的实例化
实例化相当于根据图纸,建造出房子。使用new 关键字来创建对象。
Cat cat=new Cat();
cat.eat();
cat.sleep();
4.成员变量的初始化
1)默认初始化
注意分清什么是成员变量,什么是局部变量(类中的是成员变量,方法中的是局部变量)。局部变量如果不初始化,编译会报错。如果针对对象中的成员变量没有显示的进行初始化,此时存在一个默认值。
规则:
- 数字类型(包括整数和浮点数)默认初始化为0
- 布尔类型,默认初始化为false
- 引用类型(String,数组,类),默认初始化为null
- char类型,默认初始化为'\u000'
示例:
class Init{
int a;
long b;
double c;
String d;
boolean e;
}
public class Blog{
public static void main(String[] args) {
Init init=new Init();
System.out.println(init.a);
System.out.println(init.b);
System.out.println(init.c);
System.out.println(init.d);
System.out.println(init.e);
}
}
2)就地初始化
这个不难理解,直接看下面的例子就懂了~
class Init{
int a=2;
long b=20;
double c=1.0;
String d="";
boolean e=true;
}
3)构造方法初始化
构造方法的特点:
- 构造方法的名字名和类名相同
- 不需要写return语句
- 不需要手动显示的调用,而是在new的时候,就会被自动的调用
- 构造方法支持重载
使用构造方法初始化,比前面两种初始化方式更灵活强大:
- 构造方法可以传递一些参数,动态的获取到要针对对象初始化的值
- 构造方法可以支持重载,可以有多个构造方法,不同的构造方法所支持的参数的个数或者类型是不同的。正因为这样的重载,就可以通过不同的方式来针对某个对象进行初始化。
示例:
class Init{
String name;
public Init(String name){
this.name=name;
}
}
public class Blog{
public static void main(String[] args) {
Init init=new Init("构造方法初始化示例");
System.out.println(init.name);
}
}
结果
分析:在new对象的时候,就会自动调用构造方法,在传入的参数的时候,形参的name和当前创建的对象的成员变量名name重名了,所以编译器无法区分把形参name赋值给形参还是赋值给当前对象的成员变量name,所以可以使用this关键字来区分,表示当前对象,this相当于“我”,看当前的方法是被哪个对象调用的,this就表示是谁。所以通过传入构造的参数就可以成功初始化我们的成员变量name,最终打印出初始化的成果~
关于this的一些注意事项:this只能在成员变量中使用,在构造方法中,必须放在第一行,且只能调用一个.this()的形式调用当前类的另外一个构造方法。
4)代码块初始化
这个也是看下面的例子也就会了,使用的比较少,但是也有特殊的作用~
class Init{
String name;
{
System.out.println("你好呀~我是代码块初始化时打印的哦~~");
name="hello";
}
}
public class Blog{
public static void main(String[] args) {
Init init=new Init();
System.out.println(init.name);
}
}
结果
5)实例化对象的初始化执行顺序
默认初始化->就地初始化和代码块初始化谁先出现先执行谁->构造方法初始化
5.toString
任何一个类里面都可以有toString这个方法,通过这个方法,就可以把一个对象转成一个String,转成String之后,就可以把String打印出来,或者保存在文件中,或者通过网络发送出去...
toString这个方法一般不需要显式调用(显式调用也完全可以),不写显式调用的时候,当代码中把这个对象当成字符串来使用的场景中,就会自动触发toString(比如System.out.println())
示例:
class Init{
int year;
int month;
int day;
//构造方法
public Init(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
//toString方法
public String toString(){
return this.year+"/"+this.month+"/"+this.day;
}
}
public class Blog{
public static void main(String[] args) {
Init init=new Init(2020,1,20);
System.out.println(init);
}
}
结果
6.关于static
如果一个成员没有被static修饰,这是一个对象的属性/成员/字段
如果一个成员被static修饰了,这就是这个类的属性/成员/字段,使用的时候要用类名.XX的方法使用,只有一份(就相当于只有一份图纸,图纸也有自己的属性,比例尺呀啥的~,不会因为根据图纸创建出的对象的不同而导致图纸的属性变了)
class Person{
String name="一颗苹果";
static String project="Java";
}
public class Blog{
public static void main(String[] args) {
System.out.println(Person.project);
}
}
7.访问限定符
属性或者方法前可加这些限定符:
- private:类内部可访问
- default:同包之间访问
- protected:不止同包,而且可被其他包中的子类访问
- public:可在类外部访问
类前面只能加public或者啥都不加
该使用哪种访问权限?一般是希望代码封装程度更好一些,能不被外面知道的东西,就尽量别暴露出去,能使用private尽量用private。
8.代码块
是使用{}定义的一段代码,有四种:
1)普通代码块:定义在方法中的代码块
2)构造块:定义在类中的代码块(不加修饰符),一般用来初始化成员变量,上面举栗子了~
3)静态块:使用static定义的代码块,一般用于初始化静态成员属性
class Person{
static String name;
static{
name="一颗苹果";
}
}
public class Blog{
public static void main(String[] args) {
System.out.println(Person.name);
}
}
注意:静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。
static修饰的代码块执行始终在普通代码块之前,static代码块是在类加载的时候执行的,普通代码块是在创建实例的时候执行的,类加载始终是在创建实例之前(类加载只进行一次)
4)同步代码块
9.内部类
将一个类定义在另一个类中或者一个方法中里面,这样的类称为内部类。
1)静态内部类
static修饰,表示是类相关的
public class Blog{
static class B{
}
public static void main(String[] args) {
B b1=new Blog.B();
B b2=new B();//也可以省略前面的绑定
}
}
和静态变量静态方法类似,静态内部类也是和当前类(Blog)绑定的,使用的时候也是使用当前的类Blog调用的。
2)匿名内部类(相对比较常用)
是在一个方法或者代码块中定义的类,没有显示申明类的名称.
public class Blog{
public static void main(String[] args) {
// 定一个匿名内部类
A a=new A(){
};
}
}
class A{
}
可以看到上面,A a=new A()后面有一个{},表示可以重写方法,对于A中的方法进行重写,其实也就相当于重新创建了一个类(重写之后的类的功能和之前的类的功能不同了),但是这个类我们并没有给它起名字,所以就叫做匿名内部类。
()里面是调用的构造方法,{}里面是重写/定义的方法,只是一个定义,没有产生方法的调用.
public class Test {
public static void main(String[] args) {
A1 a=new A1(){
public String func(String s){
System.out.println("hello");
return s;
}
};
System.out.println(a.func("world"));
}
}
class A1{
public String func(String s){
return s;
}
}
分析:
上面的代码中,我们可以看到有一个类A1,它里面有一个方法func(),功能是将调用时传入的参数打印出来。但是我们在main方法中,实际想要根据A1创建对象时,希望它的实例调用func这个方法时不仅能实现原本的func()的功能,还期望它有别的功能,如上例中,还能打印出"hello",所以就要对A1中的func进行重写,于是我们在A1 a=new A1()后面加上大括号,里面写我们重写的内容,此时的a调用func方法的结果就如下所示:
经常用在需要实例化某个对象,但需要重写方法时,比如new接口,抽象类就是使用匿名内部类较多的方式~~
3)成员内部类
public class Test{
//定义一个成员内部类C
public class C{
}
public static void main(String[] args) {
C c=new Test().new C();
}
}
4)局部内部类(没啥用)
局部内部类的作用域和局部变量的作用域相似,在方法或代码段中定义,作用域和匿名内部类的作用域相同。
public class Test {
public static void main(String[] args) {
class D extends A{
}
System.out.println(new D());
}
}
class A{
}
和匿名内部类相似,只是显示申明了名字
10.类和对象的内存布局
JVM中的内存区域除了堆和栈之外,还有一个非常重要的区域,方法区。这些是JVM自己从系统申请过来的内存的进一步的划分。
栈:方法和方法之间的调用关系
堆:new出来的对象/实例
方法区:存的是一个一个的“类相关的信息”(每个类的方法的二进制的指令也是在这里),对于属性来说,如果属性是一个实例属性,那么不在方法区,而是跟着实例走(实例一般在堆上),如果一个属性是一个类属性(static),那么也就在方法区中。对于方法来说,不管是加static还是不加,对应的内容都是在方法区中。