前面的章节知识(点击跳转即可哦)
目录
8 类和对象 - 上
8.1 类和对象的认识
对象就是真正存在的实体,可以具体到个体上。
在描述对象的时候,发现这些对象具有的一些共同的特征:
- 具有相同的属性 (比如都是人,都有五官,都会说话)
- 具有相同的行为 (都要吃穿住行)
因此把具有相同属性和行为的一类
对象 抽象为类,使用类来描述这类对象
的特性。
比如作者我自己DJL,我属于人的这一大类,要想找我肯定是 先是人 -> 再是我DJL。
类 —> 抽象的概念,人类,植物,鸟类,就是无法具体到一个 个体
对象 —> 在某个类中的一个实体,真正存在的,当有了对象之后,这些属性就有了属性值,这些行为就有了相应的意义。
8.2 类和类的对象
类是描述某一对象的统称,对象是这个类的一个实例而已
这一类对象所具备的共同属性和方法都在类中定义
创建类的语法
class 类名称{
//实例属性,成员属性
//实例方法,成员方法
}
在Java中,一个源文件(*.Java)只可以存在一个主类,public class
看具体代码:
package ClassesAndObjects;
public class Test {
public static void main(String[] args) {
Person per = new Person();
Person per1 = new Person();
per.name = "DJL";
per.age = 18;
per.sex = "男";
per.print();
per1.print();
}
}
class Person{
String name;
String sex;
int age;
//等等
void print(){
System.out.println("姓名:" + name + ",性别:" + sex + ",年龄:" + age);
}
}
输出结果:
姓名:DJL,性别:男,年龄:18
姓名:null,性别:null,年龄:0
看到输出的第二行,姓名:null,性别:null,年龄:0
,就可以知道成员变量都有默认值,默认值就是这个变量所在的类的默认值。
小结;
- 类的命名使用有意义的大驼峰单词命名法,从第一个单词开始首字母就大写,多个单词都是首字母大写 。
- 类中定义的成员变量都有默认值。
8.3 类的实例化
类相当于一个蓝图,一个范本,是抽象的概念
有了类之后我们就可以根据类来产生一个具体的对象
//类名称 引用名称 = new 类名称();
引用名称
是这个对象的引用,
new 类名称()
是对象,在堆中存储
当产生一个类的对象之后,我们就可以使用 ” . “操作符来使用该对象的属性和方法。
看代码:
package ClassesAndObjects;
public class Test {
public static void main(String[] args) {
Person per = new Person();
per.print();
}
}
class Person{
String name = "DJL";
String sex = "男";
int age = 18;
void print(){
System.out.println("姓名:" + name + ",性别:" + sex + ",年龄:" + age);
}
}
输出结果:
姓名:DJL,性别:男,年龄:18
成员变量可以在类定义时进行赋值,成员变量就地初始化。
8.3.1 关于引用数据类型的特殊值 null
null
在Java 中表示 ”空引用“,只有名字没有保存任何堆内存中的任何地址,如果直接使用值为 null
的引用去使用“ . ”操作符对任何属性和方法(成员变量和成员方法)都会报错。
看代码:
package ClassesAndObjects;
public class Test {
public static void main(String[] args) {
Person per = new Person();
//此时name 的默认值为 null
System.out.println(per.name.length());
}
}
class Person{
String name;
String sex;
int age;
void print(){
System.out.println("姓名:" + name + ",性别:" + sex + ",年龄:" + age);
}
}
编译报错:
NullPointerException
代表调用了一个值为null的引用。
总结:
类:一组具有相同特征对象的抽象,类中定义了所有该类对象所共同具备的属性和方法。
对象:某个类的一个具体的实体,使用new关键字创建一个对象。
所有类的对象都是引用数据类型,对于引用数据类型来说,默认值为 null。
NullPointerException
表示空指针异常,一定使用了一个值为null的引用去访问成员属性或成员方法了。
8.4 static 关键字
看见static
就要想到,和对象无关,静态属性->表示共有的含义。
static的作用有:
- 修饰属性,类属性,类变量
- 修饰方法,类方法,工具方法
- static修饰代码块,静态代码块
- static修饰内部类,静态内部类(3和4暂时先不说,后面会补)
8.4.1 static修饰属性
static修饰的属性称为类属性,类变量,所有对象共享。
那为什么要引入这个static变量呢?
比如我们在创建一个类中,这个类中有一个成员变量是sex,所有的对象在堆中存储自己的sex属性,当这个类中的很多对象的sex属性都是男性时,那这个属性的值是很多对象所共有的,就可以使用static修饰这个属性,该属性就被称为静态属性。
static String sex = "男";
当一个成员变量被static关键字修饰,他就表示类的属性,该类的所有对象共享这个属性,所有对象的属性值大家都一样。
static修饰的属性在JVM的方法区存储,所有该类对象共享此属性。
static修饰的属性与对象无关,直接通过类名称就可以访问,无需通过对象进行访问。
调用new Person() 来产生Person的对象,先要有Person类才能产生对象。
首先将Person类加载到内存中,Person中的所有static变量就会被加载到方法区中。
package ClassesAndObjects;
public class Test {
public static void main(String[] args) {
System.out.println(Person.sex);
}
}
class Person{
String name = "张三";
int age = 18;
static String sex = "男";
}
输出结果为:
男
那么问大家一个问题,在Java中,能否在一个方法的内部定义一个static变量?
答案是 不能,在方法中定义的变量都是局部变量,局部变量都是存储在栈中的,static变量存储在方法区,不可能定义一个既在栈中,又在方法区的变量。
final 和 static 有什么区别?
class Person{
String name = "张三";
final int age = 18; //称为成员常量,都在堆中存储,每个对象在堆中都有这个常量
static String sex = "男"; //静态变量,在方法区存储,类的所有对象共享这个属性
}
final int age = 18; //称为成员常量,都在堆中存储,每个对象在堆中都有这个常量
age 这个属性,成员常量,在类定义的时候就赋值为 18,不可更改,Person的所有对象都有age属性,值都一样,既然这样的话,就可以把这个属性定义为 static final
,存储在方法区,全局唯一。
在类中定义常量,一般都会使用全局常量,static final 共同修饰。
常量的命名规则:
所有单词全部大写,多个单词使用下划线分割。
eg: static final String MY_SEX = “男”;
总结:
- static变量称为 类属性,在方法区存储,该类的所有对象共享此变量
- 若在类中定义了常量(定义时赋值),一般我们使用
static
和final
共同修饰,称为全局常量 - 要使用类属性,通常直接通过 类名称.属性名称(类属性与对象无关,包括该类的null引用),不推荐使用对象来调用,不规范。
8.4.2 static 修饰方法
static 修饰方法,是静态方法,用于类方法,工具方法
static 修饰的方法也是通过类名称直接方法,没有对象就可以访问。
public static void main(String[] args){}
为什么主方法是个静态方法?
主方法是一个程序的入口,如果主方法是成员方法,那他就需要通过对象进行调用,但是程序的入口都没有,对象肯定不会产生。
程序从主方法开始执行,主方法是静态方法,就可以直接调用,无需产生对象。
static : 静态,没有对象就能访问的属性和方法,静态方法没有该类对象就能访问
成员域:成员方法和成员变量必须通过对象来调用,必须得有对象才能访问
a. 在静态方法中只能调用静态方法或者静态属性,static家族之间可以相互调用。不能直接调用成员方法和成员属性,必须通过对象来调用
b. 在成员方法中既可以调用成员方法,也可以调用静态方法(此时已经产生了该类对象,一定是可以访问静态域)。
例如:工具类的方法设计为static方法
Arrays.sort(int[])
Arrays.coppyOf()
都是通过Arrays提供的操作数组的方法,设计为static方法
8.5 封装
面向对象一共有三大特性:封装,继承和多态。
封装:具有保护性和易用性(封装就有很多种表达形式)。private
实现属性或方法的封装只是封装的其中一种。
对于银行卡这个类,银行卡的卡号,密码,余额三个属性,如果这三个属性直接暴露在外面,是不合理的,不安全。 所以不能让这些属性可以提供对象直接访问,这就是封装的保护性
再比如对于饮水机这个类,对于饮水机是怎样工作的,流程是什么,对于用户来说,用户是不关注的,只需要一按(方法,方法的内部把饮水机的属性进行调配与运转),就能够出来需要的热水。封装的易用性
在Java中,所谓的权限修饰符,指的就是你修饰的属性,方法,类,可见的范围有多大。
一共有四大访问修饰符,可见的范围从小到大依次为:
private < default < protected < public
- private:代表私有的,被private修饰的属性和方法,只在当前类的内部可见,出了类的 { },对外部就完全隐藏了,外部不知道其存在。
- default:包访问权限,不需要写这个关键字,什么权限也没有
- protected:继承访问权限
- public:公共的,公开的。被public修饰的属性和方法,在当前程序中都是可见的,都是可以使用的
看代码:
package ClassesAndObjects;
public class Test {
public static void main(String[] args) {
Card card = new Card();
System.out.println(card.cardNum);
//card.cardNum此时会报错,因为main存在于 Card类的外部,所以无法访问card.cardNum
}
}
//被private修饰,表示私有的
class Card{
private int cardNum = 123456; //卡号
private double money = 214.4; //余额
private String passworfd = "123"; //密码
//在类的内部,private修饰的是可见的
}
那我们想在类的外部去使用这些私有属性,就要使用类提供的getter(取值)和setter(修改值)
对于哪些属性需要提供getter,让外部可见,哪些属性需要提供setter,让外部修改,-都要根据这个属性的特征来决定
看代码:
package ClassesAndObjects;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Card card = new Card();
System.out.println(card.getCardNum());
System.out.println(card.getMoney());
//修改密码
card.setPassworfd(scanner.nextLine());
System.out.println(card.getPassworfd());
}
}
class Card{
private int cardNum = 123456; //卡号
private double money = 214.4; //余额
private String passworfd = "123"; //密码
public int getCardNum() {
System.out.println("查看卡号");
return cardNum;
}
public double getMoney() {
System.out.println("查看余额");
return money;
}
public String getPassworfd() {
System.out.println("查询密码");
return passworfd;
}
public void setPassworfd(String passworfd) {
this.passworfd = passworfd;
System.out.println("修改密码成功");
}
}
在IDEA实际应用的时候,可以通过 右键 看到 Generate
,快捷键是 Alt+insert
,来快速生成getter和setter。
那private关键字能否修饰一个外部类?
不能,类定义出来就是要产生对象的,让外部进行使用,private修饰一个类,定义后,外部根本不知道,怎么进行使用
default:包访问权限,不需要写这个关键字,什么权限也没有
关于包访问权限,以后的代码都在一个项目中实现,不可能把所有类都放在一个文件夹下,这个时候就需要“包”,包实际上就是文件夹。
所谓的包访问权限,就是当前文件夹下可见。
创建包时,建议 包命名使用全小写,多个单词下划线分割
package person; //表示在这个包中
public class Person{ //表示 Person这个类在person这个包中
public static void main(String[] args){
}
}
包访问权限指的是 权限啥也没写,默认就是包访问权限。
对于包访问权限来说,只有当前包的内部可见(子包,子文件夹都不可见)
包(文件夹)最大的意义在于 不同的包中类可以重名,类的全名称是 包名.类名
person.Person 和 test.Person,这两个类名字可以重复,因为在两个不同的包下。
总结:
static 和对象无关,表示一个类的属性和方法
- static属性表示共享变量的概念,存放在方法区,所有该类的对象共享此变量,直接使用类名称访问。(也可以通过对象访问,但是不规范)
- static方法表示工具方法,直接通过类名称访问,与具体的某个对象无关(Arrays.copyOf等等)
- static不能直接修饰一个外部类,会编译出错
静态方法中不能直接调用非静态方法或属性(除非产生对象),但是可以访问静态变量和方法。
成员方法中,既可以调用成员变量或方法,也可以调用静态变量和方法。
private: 当前类的内部可见,出了这个类就无法使用
当一个属性被private封装后,外部使用必须通过该类提供的getter 和 setter方法(其实就是普通的成员方法,只是命名上有规则)
要是对大家有所帮助的话,请帮我点个赞吧。