JAVA基础

二.面向对象

1. 什么是类?什么是对象?

①现实生活是由很多很多对象组成的,基于对象抽出了类
②对象:软件中真实存在的单个的个体/东西
③类:类型/类别,代表一类个体
④类是对象的模板/模子,对象是类的具体的实例
⑤类中可以包含:
对象的属性 / 特征 / 数据 --------------------- 成员变量
对象的行为 / 动作 / 功能 --------------------- 方法
一个类可以创建多个对象

2. 如何创建类?如何创建对象?如何访问成员?

代码演示二如下:

public class Student {
//成员变量----------描述对象的属性
String name;
int age;
String address;
//方法-------------描述对象的行为
void study(){
System.out.println(name+"在学习...");
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
}
public class StudentTest {
public static void main(String[] args) {
//创建一个学生对象
Student zs = new Student();
//访问成员变量
zs.name = "zhangsan";
zs.age = 24;
zs.address = "广东深圳";
//调用方法
zs.study();
zs.sayHi();
Student ls = new Student();
ls.name = "lisi";
ls.age = 25;
ls.address = "黑龙江哈尔滨";
ls.study();
ls.sayHi();
//1)创建了一个学生对象
//2)给成员变量赋默认值
Student ww = new Student();
ww.study();
ww.sayHi();
}
}

3.方法的签名:方法名+参数列表

4. 方法的重载(overload/overloading)------------------------便于用户的调用

①发生在同一类中,方法名相同,参数列表不同

②编译器在编译时会根据方法的签名自动绑定调用方法

代码演示如下:

public class OverloadDemo {
public static void main(String[] args) {
Aoo o = new Aoo();
o.show();
o.show("zhangsan");
o.show(25);
o.show("zhangsan",25);
o.show(25,"zhangsan");
}
}
class Aoo{
void show(){}
void show(String name){}
void show(int age){}
void show(String name,int age){}
void show(int age,String name){}
//int show(){ return 1;} //编译错误,重载与返回值类型无关
//void show(String address){} //编译错误,重载与参数名称无关
}

6.构造方法:构造函数、构造器、构建器----------------------------------复用给成员变量赋初值

①作用:给成员变量赋初始值

②语法:与类同名,没有返回值类型(void都没有)

③调用:在创建(new)对象时被自动调用

④若自己不写构造方法,则编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供

⑤构造方法可以重载

public class Student {
String name;
int age;
String address;
//给成员变量赋初始值
Student(String name,int age,String address){
this.name = name;
this.age = age;
this.address = address;
}
void study(){
System.out.println(name+"在学习...");
}
void sayHi(){ //默认给了咱们一个this
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
}
public class ConsDemo {
public static void main(String[] args) {
//Student zs = new Student(); //编译错误,Student类中没有无参构造方法
Student zs = new Student("zhangsan",25,"LF");
Student ls = new Student("lisi",24,"JMS");
zs.sayHi();
ls.sayHi();
}
}

⑥.this:指代当前对象,哪个对象调用方法它指的就是哪个对象

只能用在方法中,方法中访问成员变量之前默认有个 this.
this 的用法:
this. 成员变量名 ---------------------- 访问成员变量
当成员变量与局部变量同名时,若想访问成员变量则 this 不能省略
this. 方法名 ()--------------------------- 调用方法 ( 一般不用 ----------- 了解 )
this()------------------------------------- 调用构造方法 ( 一般不用 ----- 了解 )

null:表示空,没有指向任何对象。

若引用的值为 null ,则该引用不能进行任何点操作了,若操作则发生 NullPointerException 空指针异常。

引用类型数组

                                给引用类型数组元素赋值时,需要new个对象
                                
代码演示如下:
Student[] oses = new Student[3];
oses[0] = new Student();
oses[1] = new Student();
oses[2] = new Student();

                                若想访问元素的数据,需要通过数组元素去打点

Soudent[] oses = new Soudent[3]; //创建学生数组对象
oses[0] = new Soudent(); //创建学生对象
oses[1] = new Soudent();
oses[2] = new Soudent();
System.out.println(oses[0].name); //输出第1个学生的名字
oses[1].age = 11; //修改第2个学生年龄
oses[2].h();
for(int i=0;i<oses.length;i++){ //遍历所有学生
System.out.println(oses[i].name+","+oses[i].age); //输出每个学生的姓名年龄
oses[i].h();
}

7.继承:*重点*

作用:代码复用
通过 extends 来实现继承
超类 / 父类:共有的属性和行为
派生类 / 子类:特有的属性和行为
派生类既可以访问派生类的,也可以访问超类的,但超类不能访问派生类的
一个超类可以有多个派生类,一个派生类只能继承一个超类 -------------- 单一继承
具有传递性
java 规定:构造派生类之前必须先构造超类
在派生类的构造方法中若没有调用超类构造方法,则默认 super() 调用超类的构造方法
在派生类的构造方法中若自己调用了超类构造方法,则不再默认提供
注意: super() 调用超类构造方法,必须位于派生类构造方法的第一行

7.1super:指代当前对象的超类对象

super 的用法:
super. 成员变量名 -------------------- 访问超类的成员变量 ( 一般不用,了解 )
super. 方法名 ()------------------------- 调用超类的方法 --------------------- 明天讲
super()----------------------------------- 调用超类的构造方法
public class SuperDemo {
public static void main(String[] args) {
Boo o = new Boo();
}
}
//演示派生类中调用超类的有参构造方法
class Coo{
Coo(int a){
}
}
class Doo extends Coo{
Doo(){
super(5);
}
/*
//如下代码为默认的
Doo(){
super();
}
*/
}
//演示派生类中默认调用超类的无参构造方法
class Aoo{
Aoo(){
System.out.println("超类的构造方法");
}
}
class Boo extends Aoo{
Boo(){
super(); //默认的,调用超类的无参构造方法
System.out.println("派生类的构造方法");
}
}
                                                        继承要符合is a(是)的关系

7.2向上造型:就是在多态

超类型的引用指向派生类的对象
能点出来什么,看引用的类型 ------------ 这是规定,记住就可以了
何时向上造型:
多种角色能干的事都一样的时候,可以将多种角色统一造型到超类数组中,实现代码复用
eg: 侦察潜艇 / 鱼雷潜艇 / 水雷潜艇都能移动,都能被炸弹打 ----------- 说明干的事都一样
就可以将三种潜艇统一造型到 SeaObject 数组中,这样仅需要一个 for 即可 ---------- 代码复用
public class UploadDemo {
public static void main(String[] args) {
Eoo o1 = new Eoo();
o1.e = 1;
o1.show();
//o1.f = 2; //编译错误,超类不能访问派生类的
//o1.test(); //编译错误
Foo o2 = new Foo();
o2.f = 1;
o2.test();
o2.e = 2; //正确,派生类可以访问超类的
o2.show(); //正确
//能点出来什么,看引用的类型------------这是规定,记住就可以了
Eoo o3 = new Foo(); //向上造型
o3.e = 1;
o3.show();
//o3.f = 2; //编译错误,o3是Eoo类型,所以只能访问Eoo里面的
//o3.test(); //编译错误
}
}
class Eoo{
int e;
void show(){
}
}
class Foo extends Eoo{
int f;
void test(){
}
}
超类的意义:
封装共有的属性和行为 ------------------- 实现代码复用
为所有派生类提供了统一的类型 ------- 向上造型 ( 实现代码复用 )

7.3方法的重写(override/overriding):重新写

发生在父子类中,方法名相同,参数列表相同
重写方法被调用时,看对象的类型 ------------------------- 这是规定,记住就行了

7.4. 重写与重载的区别:----------常见面试题

重写 (override) :发生在父子类中,方法名相同,参数列表相同
重载 (overload) :发生在同一类中,方法名相同,参数列表不同

7.5. packageimport

package :声明包
作用:避免类的命名冲突
同包中的类不能同名,但是不同包中的类可以同名
类的全称:包名 . 类名,包名常常有层次结构
建议:包名所有字母都小写
import :导入类
同包中的类可以直接访问,而不同包中的类不能直接访问,若想访问:
import 导入类,再访问 --------- 建议
类的全称 ------------------------------- 太繁琐,不建议

7.6访问控制修饰符:---------------------------保护数据的安全

public :公开的,任何类
private :私有的,本类
protected :受保护的,本类、派生类、同包类 ----------- 应用率低
默认的:什么也不写,本类、同包类 -------------------------java 不建议默认权限
说明:
1. 类的访问权限,只能是 public 或默认的
2. 类中成员的访问权限,如上 4 种都可以
3. 访问权限由低到高依次为: private< 默认的 <protected<public
代码演示如下:
package ooday04;
//演示访问控制修饰符
public class Aoo {
public int a; //任何类
protected int b; //本类、派生类、同包类
int c; //本类、同包类
private int d; //本类
void show(){
a = 1;
b = 2;
c = 3;
d = 4;
}
}
class Boo{ //-------------------演示private
void show(){
Aoo o = new Aoo();
o.a = 1;
o.b = 2;
o.c = 3;
//o.d = 4; //编译错误
}
}
package ooday04_vis;
import ooday04.Aoo;
public class Coo { //----------------演示同包的
void show(){
Aoo o = new Aoo();
o.a = 1;
//o.b = 2; //编译错误
//o.c = 3; //编译错误
//o.d = 4; //编译错误
}
}
class Doo extends Aoo{ //跨包继承-----------演示protected
void show(){
a = 1;
b = 2;
//c = 3; //编译错误
//d = 4; //编译错误
}
}

7.7static:静态的

静态变量:
static 修饰
属于类,存储方法区中,只有一份
常常通过类名点来访问
何时用:所有对象所共享的数据 ( 图片、音频、视频等 )
代码演示如下:
public class StaticDemo {
public static void main(String[] args) {
Eoo o1 = new Eoo();
o1.show();
Eoo o2 = new Eoo();
o2.show();
Eoo o3 = new Eoo();
o3.show();
System.out.println(Eoo.b); //常常通过类名点来访问
}
}
//演示静态变量
class Eoo{
int a;
static int b;
Eoo(){
a++;
b++;
}
void show(){
System.out.println(a+","+b);
}
}

7.8静态方法:

static 修饰
属于类,存储方法区中,只有一份
常常通过类名点来访问
静态方法中没有隐式 this 传递,所以不能直接访问实例成员
何时用:方法的操作与对象无关 ( 方法中不操作对象的属性和行为 )
代码演示如下:
public class StaticDemo {
public static void main(String[] args) {
Foo.test(); //常常通过类名点来访问
}
}
//演示静态方法
class Foo{
int a; //实例变量(对象来访问)
static int b; //静态变量(类名点来访问)
void show(){ //有this
System.out.println(this.a);
System.out.println(Foo.b);
}
static void test(){ //没有this
//静态方法中没有隐式this传递
//没有this就意味着没有对象
//而实例变量a是必须由对象来访问的
//所以如下语句发生编译错误
//System.out.println(a); //编译错误
System.out.println(Foo.b);
静态块:
由static修饰
属于类,在类被加载期间自动执行,因一个类只被加载一次,所以静态块也只执行一次
何时用:初始化/加载静态资源(图片、音频、视频等)
补充:
1. 数据(成员变量)私有化(private),行为(方法)公开化(public)
2. 成员变量分两种:
实例变量:没有static修饰,属于对象的,存储在堆中,有几个对象就有几份,通过对象/引用点来访问
}
}
//演示静态方法何时用
class Goo{
int a; //描述的是对象的属性
//在show()方法中访问了对象的属性a,说明该方法与对象有关,不能设计为static方法
void show(){
System.out.println(a);
}
//在plus()方法中不需要访问对象的属性,说明该方法与对象无关,可以设计为static方法
static int plus(int num1,int num2){
int num = num1+num2;
return num;
}
}

7.9静态块:

static 修饰
属于类,在类被加载期间自动执行,因一个类只被加载一次,所以静态块也只执行一次
何时用:初始化 / 加载静态资源 ( 图片、音频、视频等 )
代码演示如下:
public class StaticDemo {
public static void main(String[] args) {
Hoo o4 = new Hoo();
Hoo o5 = new Hoo();
Hoo o6 = new Hoo();
}
}
//演示静态块
class Hoo{
static{
System.out.println("静态块");
}
Hoo(){
System.out.println("构造方法");
}
}

7.10final:最终的、不能改变的-----------------单独应用几率低

                                                修饰变量:变量不能被改变
class Aoo{
final int a = 5;
void show(){
//a = 55; //编译错误,final的变量不能被改变
}
}
                                                修饰方法:方法不能被重写        
class Boo{
void show(){}
final void test(){}
}
class Coo extends Boo{
void show(){}
//void test(){} //编译错误,final的方法不能被重写
}
                                                修饰类:类不能被继承
final class Doo{}
//class Eoo extends Doo{} //编译错误,final的类不能被继承
class Foo{}
final class Goo extends Foo{} //正确,不能当老爸,但能当儿子

7.11static final常量:应用率高

必须声明同时初始化
常常通过类名点来访问,不能被改变
建议:常量名所有字母都大写,多个单词用 _ 分隔
编译器在编译时,会将常量直接替换为具体的数,效率高
何时用:数据永远不变,并且经常使用
public class StaticFinalDemo {
public static void main(String[] args) {
System.out.println(Hoo.PI); //常常通过类名点来访问
//Hoo.PI = 3.1415926; //编译错误,常量不能被改变
//1)加载Ioo.class到方法区中
//2)静态变量num一并存储到方法区中
//3)到方法区中获取num的值并输出
System.out.println(Ioo.num);
//编译器在编译时,会将常量直接替换为具体的值,效率高
//相当于System.out.println(5);
System.out.println(Ioo.COUNT);
}
}
class Ioo{
public static int num = 5; //静态变量
public static final int COUNT = 5; //常量
}
class Hoo{
public static final double PI = 3.14159;
//public static final int NUM; //编译错误,常量必须声明同时初始化
}

补充:

1. 数据 ( 成员变量 ) 私有化 (private) ,行为 ( 方法 ) 公开化 (public)
2. 成员变量分两种:
实例变量:没有 static 修饰,属于对象的,存储在堆中,有几个对象就有几份,通过对象 / 引用点来访问
静态变量:有 static 修饰,属于类的,存储在方法区中,只有一份,常常通过类名点来访问
一般在构造方法中对实例变量进行初始化,在静态块中对静态变量进行初始化
3. 内存管理:由 JVM 来管理的
堆: new 出来的对象 ( 包括实例变量、数组的元素 )
栈:局部变量 ( 包括方法的参数 )
方法区: .class 字节码文件 ( 包括静态变量、所有方法 )

8. 抽象方法、抽象类:

8.1抽象方法:

abstract 修饰
只有方法的定义,没有具体的实现 ( {} 都没有 )

8.2抽象类:

abstract 修饰
包含抽象方法的类必须是抽象类
抽象类不能被实例化 (new 对象 )
抽象类需要被继承,派生类:
重写超类的所有抽象方法 ---------- 变不完整为完整
也声明为抽象类 ---------------------- 不常用
抽象类的意义:
封装共有的属性和行为 ------------------- 代码复用
为所有派生类提供统一的类型 ---------- 向上造型 ( 代码复用 ) 可以包含抽象方法,为所有派生类提供统一的入口 ( 向上造型后能点出来 ) ,同时可以达内强制必须重
写的目的 ( 相当于制定了一个标准 )

8.3抽象方法/抽象类的疑问:

抽象方法存在的意义是什么?
保证当发生向上造型,通过超类的引用能点出来那个方法 ---------- 保证能点出方法来
既然抽象方法的意义是保证能点出来,那为什么不设计为普通方法呢?
设计为普通方法,意味着派生类可以重写也可以不重写,但设计为抽象方法,则可以强制派生类必须
重写 ------------ 达到强制派生类重写,统一的目的

9.内部类

9.1成员内部类:

类中套类,外面的称为外部类,里面的称为内部类
内部类通常只服务于外部类,对外不具备可见性
内部类对象通常在外部类中创建
内部类中可以直接访问外部类的成员 ( 包括私有的 )
内部类有个隐式的引用指向了创建它的外部类对象 ---------- 外部类名 .this
public class InnerClassDemo {
public static void main(String[] args) {
Mama m = new Mama();
//Baby b = new Baby(); //编译错误,内部类对外不可见
}
}
class Mama{ //外部类
private String name;
void create(){
Baby b = new Baby(); //正确
}
class Baby{ //内部类
void show(){
System.out.println(name); //简写
System.out.println(Mama.this.name); //完整写法
//System.out.println(this.name); //编译错误,this指代当前Baby对象
}
}
}

9.2匿名内部类: ------简化代码

若想创建一个类 ( 派生类 ) 的对象,并且对象只被创建一次,此时可以设计为匿名内部类
匿名内部类中不能修饰外面局部变量的值,因为该变量在此处默认为 final ------------API 时会用
常见面试题:
问:内部类有独立的 .class 吗?
答:有
public class NstInnerClassDemo {
public static void main(String[] args) {
//1)创建了Aoo的一个派生类,但是没有名字
//2)为该派生类创建了一个对象,名为o1
// ---new Aoo(){}是在创建Aoo的派生类的对象
//3)大括号中的派生类的类体
Aoo o1 = new Aoo(){
};
//1)创建了Aoo的一个派生类,但是没有名字
//2)为该派生类创建了一个对象,名为o2
//3)大括号中的派生类的类体
Aoo o2 = new Aoo(){
};
int num = 5;
num = 55;
//1)创建了Boo的一个派生类,但是没有名字
//2)为该派生类创建了一个对象,名为o3
//3)大括号中的派生类的类体
Boo o3 = new Boo(){
void show(){ //重写超类Boo的抽象show()方法
System.out.println("showshow");
//num = 88; //编译错误,匿名内部类中不能修改外面局部变量的值,
//因为该变量在此处默认为final的
}
};
o3.show(); //派生类对象o3调用派生类中的方法show()
}
}
abstract class Boo{
abstract void show();
}
abstract class Aoo{
}

补充:

1. 隐式的引用:
this :指代当前对象
super :指代当前对象的超类对象
外部类名 .this :指代当前对象的外部类对象
2. 做功能的套路:
先写行为 / 方法:
若为某个派生类所特有的功能 / 行为,则将方法设计在特定的类中
若为所有派生类所共有的功能 / 行为,则将方法设计在超类中
窗口调用:
若为定时发生的,则在定时器中调用
若为事件触发的,则在侦听器中调用 ----------------- 明天讲
3. 如何调错:
先快速锁定问题方法:
将调用方法的代码都注释掉,然后一个一个的放开,放开哪个方法出错,说明问题就出在哪个方法上
打桩:
System.out.println( 数据 );
4. 文档注释:
是功能性注释,描述整个类是干什么的,方法是干什么的,常量是干什么的。
一般写在类上、方法上、常量上。

10.接口:

是一种数据类型 ( 引用类型 )
interface 定义
只能包含常量和抽象方法 -------- 数据默认都是常量,方法默认都是抽象的
接口不能被实例化 (new 对象 )
接口是需要被实现 / 继承的,实现类 / 派生类:必须重写所有抽象方法
一个类可以实现多个接口,用逗号分隔,若又继承又实现时,应先继承后实现
接口可以继承接口
/**
* 接口的演示
*/
public class InterfaceDemo {
public static void main(String[] args) {
//Inter5 o = new Inter5(); //编译错误,接口不能被实例化
Inter5 o1 = new Doo(); //向上造型
Inter4 o2 = new Doo(); //向上造型
}
}
//演示接口的语法
interface Inter{
public static final int NUM = 5;
public abstract void show();
int COUNT = 5; //默认public static final
void test(); //默认public abstract
//int number; //编译错误,常量必须声明同时初始化
//void say(){} //编译错误,抽象方法不能有方法体
}
//演示接口的实现
interface Inter1{
void show(); //制定规范
void test();
}
class Aoo implements Inter1{
public void show(){} //重写接口的抽象方法时,必须加public权限
public void test(){} //--------遵守规范
}
//演示接口的多实现
interface Inter2{
void show();
}
interface Inter3{
void test();
}
abstract class Boo{
abstract void say();
}
class Coo extends Boo implements Inter2,Inter3{
public void show(){}
public void test(){}
void say(){}
}
//演示接口继承接口
interface Inter4{
void show();
}
interface Inter5 extends Inter4{
void test();
}
class Doo implements Inter5{
public void test(){}
public void show(){}
}

补充:

1. 关系:
类和类 ---------------------------- 继承 extends
接口和接口 ---------------------- 继承 extends
类和接口 ------------------------- 实现 implements
2. 可以向上造型为:超类 + 所实现的接口
3. 设计规则:
将所有派生类所共有的属性和行为,抽到超类中 ---------------- 抽共性
若派生类的行为都一样,设计为普通方法
若派生类的行为不一样,设计为抽象方法
将部分派生类所共有的属性和行为,抽到接口中
接口是对继承的单根性的扩展 ------------------------------- 实现多继承
接口相当于制定了一个标准、规范 ----------- 明天下午体会
------- 实现了接口,那就能干某件事,若不实现接口,就干不了那个事 ----- 明天下午体会
4. CV 大法(真实好用哈哈)

11. 多态:多种形态

意义:
同一个对象被造型为不同的类型时,有不同的功能 ------ 所有对象都是多态的 ( 明天才能体会 )
------ 对象的多态:我、水、你 ......
同一类型的引用在指向不同对象时,有不同的实现 ------- 所有抽象方法都是多态的
------ 行为的多态: cut() getImage() getScore()......
向上造型 / 自动类型转换: -------- 就是多态
超类型的引用指向派生类的对象
能点出来什么,看引用的类型
能造型成为的类型有:超类 + 所实现的接口
强制类型转换 / 向下转换,成功的条件只有如下两种:
引用所指向的对象,就是该类型
引用所指向的对象,实现了该接口或继承了该类
强转时若不符合如上条件,则发生 ClassCastException 类型转换异常
建议:在强转之前先通过 instanceof 来判断引用的对象是否是该类型
何时需要强转:若想访问的变量 / 方法在超类中没有,则需要强转
public class MultiTypeDemo {
public static void main(String[] args) {
//条件1:引用所指向的对象,就是该类型
//条件2:引用所指向的对象,实现了该接口或继承了该类
Aoo o = new Boo(); //向上造型
Boo o1 = (Boo)o; //引用o所指向的对象,就是Boo类型--------满足条件1
Inter o2 = (Inter)o; //引用o所指向的对象,实现了Inter接口----满足条件2
//Coo o3 = (Coo)o; //运行时会发生ClassCastException类型转换异常
if(o instanceof Coo){
Coo o4 = (Coo)o;
}else{
System.out.println("o不是Coo类型");
}
}
}
interface Inter{
}
class Aoo{
}
class Boo extends Aoo implements Inter{
}
class Coo extends Aoo{
}

12. 内存管理:由JVM来管理

12.1堆:

存储的是 new 出来的对象 ( 包括实例变量、数组的元素 )
垃圾:没有任何引用所指向的对象
垃圾回收器 (GC) 不定时到内存中清扫垃圾,回收过程是透明的 ( 看不到的 ) ,并不一定一发现垃圾就立
刻回收,通过调用 System.gc() 可以建议虚拟机尽快调度 GC 来回收
实例变量的生命周期:
创建对象时存储在堆中,对象被回收时一并被回收
内存泄漏:不再使用的对象还没有被及时的回收,严重的泄漏会导致系统的崩溃
建议:不再使用的对象应及时将引用设置为 null

12.2栈:

存储正在调用的方法中的局部变量 ( 包括方法的参数 )
调用方法时,会在栈中为该方法分配一块对应的栈帧,栈帧中存储局部变量 ( 包括方法的参数 ) 方法调用结束时,栈帧被自动清除,局部变量一并被清除
局部变量的生命周期:
调用方法时存储在栈中,方法调用结束时与栈帧一并被清除
方法区:
存储 .class 字节码文件 ( 包括静态变量、所有方法 )
方法只有一份,通过 this 来区分具体的访问对象

12.3 面向对象三大特征:

封装:
类:封装对象的属性的行为,作为一个整体来操作
方法:封装一段特定的业务逻辑功能
访问控制修饰符:封装的是具体的访问权限,保护数据的安全
继承:
作用:代码复用
超类:所有派生类所共有的属性和行为
接口:部分派生类所共有的属性和行为
派生类:派生类所特有的属性和行为
单一继承、多接口实现,具有传递性
多态:
所有对象都是多态的,通过向上造型来体现
所有抽象方法都是多态的,通过方法的重写来体现
向上造型、强制类型转换、 instanceof 判断

12.4 String字符串类型:

java.lang.String 类使用 final 修饰,不能被继承
String 的底层封装的是一个字符数组
String 在内存中采用 Unicode 编码格式,每个字符占用 2 个字节的空间
字符串对象一旦创建,对象内容永远无法改变,但字符串引用可以重新赋值 ( 指向新的对象 )
String 称为不变对象

412.5字符串常量池:

java String 字符串有一个优化措施:字符串常量池 ( 堆中 )
java 推荐我们使用字面量 / 直接量 ( 直接 "") 的方式来创建字符串对象,并且会缓存所有以字面量方式来创建
的字符串对象到字符串常量池中,当使用相同字面量再创建对象时将会复用常量池中的对象,以减少内存 开销
/*
使用字面量来创建字符串对象时,JVM会检查常量池中是否有该对象:
1)若没有,则会创建该字符串对象,并将其引用存入常量池中
2)若有,则直接将常量池中的对象(引用)返回---并不会创建新的字符串对象
*/
String s1 = "123abc"; //常量池还没有,因此创建该字符串对象,并存入常量池中
String s2 = "123abc"; //常量池中已经有了,直接复用对象
String s3 = "123abc"; //常量池中已经有了,直接复用对象
//引用类型==,比较的是地址是否相同-----这是规则
System.out.println(s1==s2); //true
System.out.println(s1==s3); //true
System.out.println(s2==s3); //true
s1 = s1 + "!"; //创建新的字符串对象("123abc!")并将地址赋值给s1
System.out.println(s1==s2); //false
//编译器在编译时,若发现是两个字面量相连,则会直接连接好并将结果保存起来
//如下语句相当于: String s4 = "123abc";
String s4 = "123"+"abc"; //复用常量池中的对象
System.out.println(s4==s2); //true
String s5 = "123";
//因为s5是一个变量,所以在编译期并不会直接编译好
String s6 = s5+"abc"; //创建一个新的对象存储123abc
System.out.println(s6==s4); //false

补充:成员变量是有默认值的,而局部变量是没有默认值的

面向对象自我总结大概就以上内容,补充里是我对上述内容的补充,如果觉得有用请点个赞!

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟程序员z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值