🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
✒️ 今天开始,Java基本语法模块将进行重构.以保证文章质量.
目录
- 1. 类与对象
- 1.1 如何创建类与对象
- 1.2 this引用
- 1.2.1 为什么要用this引用
- 1.2.2 何为this引用
- 1.2.3 this引用的特性
- 1.3 对象的构造及其初始化
- 1.3.1 如何初始化对象
- 1.3.2 构造方法
- 1.3.2.1调用构造方法的快捷键
- 1.3.2.2概念
- 1.3.2.3特性
- 1.3.3 默认初始化
- 1.3.4 就地初始化
- 1.4 封装
- 1.4.1 封装的概念
- 1.4.2 访问限定符
- 1.4.3 包
- 1.4.3.1 包的概念
- 1.4.3.2 导包
- 1.4.3.3 自定义包
- 1.4.3.4 基于包的访问权限
- 1.4.3.5常见的包
- 1.5 static成员
- 1.5.1 为什么要使用static成员
- 1.5.2 static修饰成员变量
- 1.5.3 static修饰成员方法
- 1.5.4 static成员变量的初始化
- 1.6 代码块
- 1.6.1 代码块的概念以及分类
- 1.6.2 普通代码块
- 1.6.3 构造代码块
- 1.6.4 静态代码块
- 1.6.5 代码块执行的顺序
1. 类与对象
1.1 如何创建类与对象
-
什么是面向对象
在面向对象的世界里,一切皆为对象,面向对象是一种解决问题的思想,主要依靠对象之间的交互完成一件事情。除了Java,面相对象的程序设计还有C++,Java语言和C++语言是当今互联网企业后端开发最主流的两门语言。 -
面向过程与面相对象
拿一个生活中的常见例子来说明,比如洗衣服,我们既可以用手洗,也可以用洗衣机洗。手洗分为很多过程,少了一个环节都不行,所以手洗比较麻烦,代码也是同样的道理,这种面相过程来程序设计,会特别麻烦,特别是在扩展和维护阶段。
但是如今我们有了洗衣机,我们就只需要把衣服放入洗衣机里,在你的面前只有衣服,人和洗衣机,这时候你不必关心洗衣服的过程,而且洗衣服的时间可以自由调节,代码也是一样,面向对象的程序设计会让你不必担心执行的过程,就像你把衣服扔进洗衣机什么都不用管一样,而且可维护性也是比较好的,就像你可以自由调节洗衣机的洗衣时间一样方便。
-
类的定义和使用
前面讲到,面相对象的程序设计关心的是现实生活中的实体,但是计算机并不知道任何现实生活中的东西,所以我们就要来用一种语法来告诉计算机这个类型的东西是个啥,长啥样,有啥用。
比如我们就拿我们可爱的小狗狗来举例子
首先我们引入类的定义格式:
class ClassName{
field//成员变量
method//成员方法
}
我们这里提出一点小建议,我们命名类名的时候尽量采用大驼峰形式,即每个单词的首字符大写。
class为定义类的关键字.
接下来我们来定义一个狗类
class Dog{
public String name;//名字
public int age;//年龄
//狗的行为
public void barks(){
System.out.println(name+"汪汪汪");
}
public void wag(){
System.out.println(name+"摇尾巴");
}
}
3.类的实例化
我们在计算机里定义了一个类,就相当于我们在计算机里有了一个新的数据类型,就和int double这种一样,而新的数据类型我们要创建一个新的变量来使用它,这个过程就叫类的实例化,也叫创建对象的过程,在Java中,我们用new关键字来实例化对象,语法格式如下
ClassName1 objectname = new ClassName1(...);
我们接着上面的的狗类来举例子
public class x {
public static void main(String[] args) {
Dog dog1=new Dog();
dog1.name="哈士奇";
dog1.age=3;
dog1.barks();
dog1.wag();
}
}
class Dog{
public String name;//名字
public int age;//年龄
public void barks(){
System.out.println(name+"汪汪汪");
}
public void wag(){
System.out.println(name+"摇尾巴");
}
}
从上述的实例化我们不难看出,其实类就是一个抽象的事物,我们需要通过实例化来对这个抽象的事物进行一个具体的描述。就比如狗,每一只狗同有这些行为和属性,但是不同家里的狗表现出的这些属性和行为是不一样的,它们是两个不一样的对象,但是它们都属于狗类。
1.2 this引用
1.2.1 为什么要用this引用
class Date {
public int year;
public int month;
public int day;
public void setday(int y,int m,int d){
year=y;
month=m;
day=d;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.setday(2023,12,4);
date.printday();
}
}
这里我们定义了一个日期类,并且创建了一个他的对象,但是如果出现了一下的问题
public void setday(int year,int month,int day){
year=year;
month=month;
day=day;
}
这时候这里的year,month,day,你怕是傻傻分不清了吧,哪个是形式参数?哪个是成员变量?这时候,我们就要引入this关键字了。
1.2.2 何为this引用
this引用指向的是当前对象(成员方法运行时候调用该成员方法的对象),在成员方法所有成员变量的操作,都是通过该引用去访问。常见的使用方法有以下几种:
- this.成员变量——>调用当前对象的成员变量
- this.成员方法——>调用当前对象的成员方法
- this——>当前对象
- this()------>当前对象的构造方法
那么,下面我们就使用this引用对上述代码进行修改
class Date {
public int year;
public int month;
public int day;
public void setday(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.setday(2023,12,4);
date.printday();
}
}
这里的this引用的是date变量中,也就是Date类一个实例化对象的成员变量,这里就可以区分开成员变量和形式参数了。
1.2.3 this引用的特性
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在"成员方法或构造方法中使用(后续介绍)"中使用
- 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
- this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收
1.3 对象的构造及其初始化
1.3.1 如何初始化对象
通过前面的知识,我们知道,在Java中定义局部变量时候,必须要初始化,否者编译器就会报错。如果是对象的话,
public class Date {
public int year;
public int month;
public int day;
public void setday(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.setday(2023,12,4);
date.printday();
}
}
就如前面类与对象中第二篇展示的一样,我们必须要通过调用一个setday方法来初始化对象的具体日期,从这段代码中,我们可以发现两个问题:
- 我们需要调用成员方法来对日期进行初始化,有什么方法可以简化一下吗?
- 局部变量在初始化才可以使用,但是为什么这里的成员变量声明之后没有给出初始值依然可以使用?
1.3.2 构造方法
1.3.2.1调用构造方法的快捷键
在idea 64编译器中,alt+insert键会调用出构造方法列表。
1.3.2.2概念
构造方法是一个特殊的成员方法,名字必须与类名相同,在创建对象的时候,由编译器自动调用,即在创建对象的时候,编译器会干两件事情:
- 为创建的对象分配内存空间
- 由编译器自动调用该对象的额构造方法
1.3.2.3特性
- 名字必须与类名相同
- 没有返回值类型
- 构造方法可以重载,程序员可根据自己的需要提供参数不同的构造方法
public class Date {
public int year;
public int month;
public int day;
public Date(){//无参构造方法
this.year=2023;
this.month=12;
this.day=5;
}
public Date(int year,int month,int day){//有参构造方法
this.year=year;
this.month=month;
this.day=day;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date1 = new Date();//调用无参
date1.printday();
Date date2 = new Date(2023,12,5);//调用有参
date2.printday();
}
}
上述两个方法便构成了重载
- 如果没有显式定义,编译器就会自动生成一个默认的不带任何参数的构造方法
public class Date {
public int year;
public int month;
public int day;
/*Date(){
}这里会有一个默认的构造方法*/
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.printday();
}
}
- 如果用户有自己定义构造方法,那么编译器便不再提供默认的构造方法(救急不救穷)
public class Date {
public int year;
public int month;
public int day;
public Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date1 = new Date();//错误,编译器找不到这样的一个构造方法
date2.printday();
}
}
- 但是我们可以通过this方法来修改上述的错误,这里的this如果后面没有任何的成员变量的话,直接跟上的是一个参数列表,就表示的是该类的构造方法.
public class Date {
public int year;
public int month;
public int day;
public Date(){
this(2023,12,5);
}//this调用对应的构造方法
public Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date1 = new Date();//错误,编译器找不到这样的一个构造方法
date2.printday();
}
}
这里需要注意的一点是this必须是构造方法中的第一条语句,否者编译失败
7. 大多数情况下都是用public修饰,有时候也会用private修饰,后面细说
1.3.3 默认初始化
在第一个大标题中,我们提出了两个问题,但是我们的第二个问题还没有提及,下面我们直接给出回答:成员变量在不初始化的时候,会有默认的初始值,在对象的空间被申请之后,如果没有就地初始化,对象中的成员变量就已经有了默认的初始值,至于初始值,注意两种类型就可以
数据类型 | 默认值 |
---|---|
boolean | false |
reference(引用类型) | null |
1.3.4 就地初始化
在声明成员变量的时候,直接给出初始值
public class Date {
public int year=2023;
public int month=12;
public int day=5;
public void printday(){
System.out.println(year+"/"+month+"/"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.printday();
}
}
1.4 封装
1.4.1 封装的概念
面向对象的程序设计有三个特点:封装继承和多态。那么什么是封装呢,通俗一点讲就是:套壳屏蔽细节,使得类更加安全。
就像我们在市场上买了一台电脑,电脑的内部是主板以及CPU等硬件,但是向用户交付产品的时候,我们总不能向用户交付一个电路板,我们需要对这些电路板进行包装,做出一台电脑应该有的样子,并在电脑的旁边提供一些接口,方便用户和电脑内部的硬件进行一系列的交流,这就对一些硬件进行了封装。
那么什么是封装呢?将数据和数据操作的方法进行有机结合,隐藏对象的属性和细节,仅对外公开接口来和对象进行交互
1.4.2 访问限定符
那么怎么实现封装呢,Java主要通过访问限定符来进行封装,访问权限用来控制方法或者字段是否可以直接在类外使用,下面是Java的四种访问限定符:
NO | 范围 | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一包中的同一类 | √ | √ | √ | √ |
2 | 同一包中的不同类 | × | √ | √ | √ |
3 | 不同包中的子类 | × | × | √ | √ |
4 | 不同包中的非子类 | × | × | × | √ |
注意:这里的default并不是关键字,指的是什么都不写的情况下,就是没有修饰限定符的时候。
这里可以形象地理解:假如一个类是一个人
- public:这个人的外貌特征,谁都可以看见
- protected:在别人那里,只有别人家的孩子们知道,但是他们的家长不知道
- default:只有自己家中的人知道,外人不知道
- private:只有自己知道,其他人都不知道
eg:假如我们创建一个“计算机”对象
public class Computer {
private String cpu;//中央处理器
private String memory;//内存
String screen;//屏幕
public String brand;//品牌
public Computer(String cpu,String memory,String screen,String brand){
this.cpu=cpu;
this.memory=memory;
this.screen=screen;
this.brand=brand;
}
public void poweron(){
System.out.println("开机");
}
public void poweroff(){
System.out.println("关机");
}
}
public class TestComputer {
public static void main(String[] args) {
Computer computer=new Computer("intel 7","32G","16.1","hp");
System.out.println(computer.brand);
System.out.println(computer.screen);
//System.out.println(computer.cpu);错误,cpu为privat类型,不可在类外访问
}
}
1.4.3 包
1.4.3.1 包的概念
我们为了更好地管理类,把多个类收集在一起成为一组,称为包,说的再直白一些,就是文件夹,有点类似于目录。只不过现在文件夹中装的是一个个的类。
包是对类、接口等的封装机制的体现,一种对类或者接口的很好的组织方式,这里要注意的是:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可
1.4.3.2 导包
导包,即导入包中的类,关键字为import,Java中已经提供了很多现成的类供我们使用,如Date类。我们下面通过代码来演示,我们可以通过Date类得到一个时间戳。
import java.util.Date;//导包
public class Main {
public static void main(String[] args) {
Date date=new Date();
System.out.println(date.getTime());
}
}
如果不知道导入其中一个包中的哪个类,可以使用通配符“*”。
import java.util.*;
public class Main {
public static void main(String[] args) {
Date date=new Date();
System.out.println(date.getTime());
}
}
但是我们一般建议导包的时候要明确类名,避免出现冲突的情况
若包中有静态方法和字段,可使用import static来导入,例如:import static java.lang.Math.*
1.4.3.3 自定义包
1 基本规则
- 在文件的最上方加上一个package语句来指定该代码在哪个包中
- 包名需要尽量指定为唯一的名字
- 包名和代码路径相匹配,例如创建com.by.demo1的包,对应的路径为com/by/demo1
- 若一个类没有package语句,则会被放到idea默认的src包下
2 操作步骤
- 在idea中新建一个包,如图所示
- 在弹窗中命名包名
- 在包中创建类
- 我们看到类已经被创建了,包含了package语句,路径也是对应的
1.4.3.4 基于包的访问权限
我们还是拿上面的计算机类来举例
package com.by.demo1
public class Computer {
private String cpu;//中央处理器
private String memory;//内存
String screen;//屏幕
public String brand;//品牌
public Computer(String cpu,String memory,String screen,String brand){
this.cpu=cpu;
this.memory=memory;
this.screen=screen;
this.brand=brand;
}
public void poweron(){
System.out.println("开机");
}
public void poweroff(){
System.out.println("关机");
}
}
package com.by.demo2
public class TestComputer {
public static void main(String[] args) {
Computer computer=new Computer("intel 7","32G","16.1","hp");
System.out.println(computer.brand);
//System.out.println(computer.screen);错误,screen为默认类型,不可在包外的其他类访问
//System.out.println(computer.cpu);错误,cpu为privat类型,不可在类外访问
}
}
1.4.3.5常见的包
- java.sql:做数据库会用到
- java.util:工具程序包,如ArrayList,List类都在这个包中,后期学习数据结构会用到
- java.net:网络开发会用到
- java.lang:系统常用基础类,如String,Object,从jdk1.1之后就会自动导入
1.5 static成员
1.5.1 为什么要使用static成员
有一些通过类实例化出的对象,它们具有相同的特点,在实例化一个类时候,每次都实例化相同的属性或方法,显得有些麻烦,所以我们便引入了static成员。
static成员,又叫静态成员,也可以称作类成员,其不属于某个具体的对象,它是所有对象索共有的。下面我们拿“学生类”来举例。
public class Student {
public String name;
public int age;
public String classroom;
public Student(String name, int age, String classroom) {
this.name = name;
this.age = age;
this.classroom = classroom;
}
public void classbegin(){
System.out.println("在同一间教室上课");
}
public static void main(String[] args) {
Student s1=new Student("张三",20,"111");
s1.classbegin();
Student s2=new Student("李四",19,"111");
s2.classbegin();
}
}
从这段代码中,我们发现,张三和李四上课的教室是同一间教室,都是111班,这样每一次都对classroom进行初始化和每次调用classbegin方法显得过于麻烦,所以我们对以上代码使用类成员进行改进。
public class Student {
public String name;
public int age;
public static String classroom="111";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static void classbegin(){
System.out.println("在同一间教室上课");
}
public static void main(String[] args) {
Student s1=new Student("张三",20);
Student s2=new Student("李四",19);
Student.classbegin();//这里先不用管,讲到后面会明白
}
}
1.5.2 static修饰成员变量
static修饰的成员变量,称为静态成员变量
静态成员变量的特点:
- 不属于某一个对象,是类的属性,是所有对象所共有的(最大的特点)
- 既可以通过对象访问(会报警告),也可以通过类名访问,更推荐第二种。
- 类变量储存在方法区中
- 生命周期伴随类的一生(随着类的加载而创建,随着类的销毁而销毁)
1.5.3 static修饰成员方法
我们对以上“学生类”代码进行一些简单修改
public class Student {
public String name;
public int age;
private static String classroom = "111";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static String classbegin() {
//System.out.println(this.name); error
return classroom;
}
}
public class Test {
public static void main(String[] args) {
Student s1=new Student("张三",20);
Student s2=new Student("李四",19);
System.out.println(Student.classbegin());
}
}
我们把类中的classroom进行了封装限定,并通过公开的classbegin接口来获取到classroom,并把主函数移动到了一个不同的类当中,在主函数中使用类名来访问classbegin方法。
从以上代码,我们可以看出static修饰成员方法的一些特点:
- 不属于某个具体的对象,是类方法
- 既可以通过对象访问(会报警告),也可以通过类名访问,更推荐第二种。
- 不可以在静态方法中访问任何非静态成员变量
- 同上面第三条的原理在静态方法中不可以调用任何非静态的方法
- 但是反过来,非静态的成员方法可以调用静态成员变量或者静态成员方法,举例如下。
public class Student {
public String name;
public int age;
private static String classroom = "111";
public void test(){
classbegin();//未报错
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static String classbegin() {
return classroom;
//this.test; error
}
}
public class Test {
public static void main(String[] args) {
Student s1=new Student("张三",20);
Student s2=new Student("李四",19);
System.out.println(Student.classbegin());
}
}
静态方法无法重写,无法实现多态(后面会讲到)
1.5.4 static成员变量的初始化
注意:static成员变量不可以放在构造方法中来初始化,因为构造方法是一个类创建实例化对象的时候自动调用的方法,而静态成员变量和对象这个概念压根不搭边,也就不可以在构造方法中调用.
他的初始化方法只有两种,就地初始化和静态代码块初始化
- 就地初始化是指:在定义的时候就给出初始值,就如上面的“学生类”
private static String classroom = "111";
- 静态代码块初始化
后续会讲到
1.6 代码块
1.6.1 代码块的概念以及分类
使用{}定义的一段代码称为代码块,代码块可以分为以下四种:
- 普通代码块
- 构造代码块
- 静态代码块
同步代码块(后续多线程问题会谈到)
1.6.2 普通代码块
定义在方法中的代码块,这类代码块不需要条件,一定会被执行,但是这种代码块相对少见
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
1.6.3 构造代码块
定义在类中的代码块(不加修饰符)。也叫实例代码块。构造代码块一般用于初始化实例成员对象。还是拿我们熟悉的“学生类”来举例。
public class Student{
//实例成员变量
private String name;
private String gender;
private int age;
private double score;
public Student() {
System.out.println("I am Student init()!");
}
//实例代码块
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Student stu = new Student();
stu.show();
}
}
1.6.4 静态代码块
使用static修饰的代码块称为静态代码块,一般用于初始化静态成员变量
public class Student{
private String name;
private String sex;
private int age;
private double score;
private static String classRoom;
//实例代码块
{
this.name = "bit";
this.age = 12;
this.gender = "man";
System.out.println("I am instance init()!");
}
// 静态代码块
static {
classRoom = "bit306";
System.out.println("I am static init()!");
}
public Student(){
System.out.println("I am Student init()!");
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
这里可以返回去看一下上一篇文章中静态成员变量的初始化
注意事项:
- 静态代码块不管生成多少个对象,其只会执行一次
- 静态成员变量是类的属性,就和我们上一篇文章提到的类成员性质一样
- 实例代码块只有在创建对象的时候才会执行
1.6.5 代码块执行的顺序
静态代码块>实例代码块>构造方法
原理解释:
在代码执行的时候,先要加载出类,才可以对类进行实例化,然而静态代码块属于类的属性,只要类被加载,就会执行,不管有没有对这个类做出实例化,所以静态代码块>实例代码块,其次,创建一个对象的时候,分为两步,第一步是给创建的对象分配内存空间,其次调用对象的构造方法,所以实例代码块>构造方法