类和对象的初步认识
在讲类和对象之前,我们我们需要先真正理解什么是面向对象和面向过程。 我们以洗衣服举例: 面向过程,如上图,你洗衣服关注的是每一步我应该干什么,有严格的顺序性。
面向对象,如上图,洗衣服是“人”、“衣服”、“洗衣机”、“洗衣粉”四个对象交互完成的,你不用关心衣服扔进洗衣机然后洗衣机怎么洗,你只需要把洗衣粉、衣服给洗衣机即可,然后洗衣机开始洗衣服。
面向对象你只需要把握以下三点即可编程 1.找对象 2.创建对象 3.使用对象
那对象是怎么来呢?对象是由类而来的 比如说:我们是人嘛,每个人都有共同的属性——姓名、性别、年龄。。。 也有很多共同的行为——吃饭、睡觉、上学、玩游戏。。。 那由这些共同的属性和行为我们可以放到一个模板(我们可以称这个模板为人)里,由这个模板可以产生很多的对象,而这个模板也就是一个类。
以大白话说就是:人类是一个类(它不是一个实体),单独到个人(实体)是一个对象。
创建对象是通过new关键字——把类实例化 (图片来自比特就业课)
提示:以下是本篇文章正文内容,下面案例可供参考
一、类和对象的实例化
基本语法:
Class 类名称{
field;
method;
}
类名称 对象名 =new 类名称();
实战举例:
class Person{
public String name;
public int age=18;
public void eat(){
System.out.println(name+"正在吃饭");
}
public void sleep(){
System.out.println(name+"正在睡觉");
}
}
public class test {
public static void main(String[] args) {
int a =1;
Person xiaoHei=null;
Person xiaoMing=new Person();
System.out.println(xiaoMing.age);
System.out.println(xiaoMing.name);
System.out.println(xiaoMing.num);
xiaoMing.num=1000;
System.out.println(xiaoMing.num);
xiaoHei=new Person();
System.out.println(xiaoHei.num);
xiaoMing.eat();
}
}
普通成员变量需要
二、类的成员
2.1字段/属性/成员变量
代码如下(示例):
class Person{
public String name;
public int age=18;
}
public class test {
public static void main(String[] args) {
int a =1;
Person xiaoHei=null;
Person xiaoMing=new Person();
System.out.println(xiaoMing.age);
System.out.println(xiaoMing.name);
System.out.println(xiaoMing.num);
xiaoMing.num=1000;
System.out.println(xiaoMing.num);
xiaoHei=new Person();
System.out.println(xiaoHei.num);
}
}
2.2方法
class Person{
public void eat(){
System.out.println(name+"正在吃饭");
}
public void sleep(){
System.out.println(name+"正在睡觉");
}
}
public class test {
public static void main(String[] args) {
Person xiaoMing=new Person();
xiaoMing.eat();
}
}
2.3static关键字
static修饰的静态成员变量
import java.util.Arrays;
class Person{
public int age;
public static int count;
}
public class test {
public static void main(String[] args) {
Person p1=new Person();
Person p2=new Person();
p1.count++;
p1.age++;
System.out.println(p1.count);
System.out.println(p1.age);
p2.count++;
p2.age++;
System.out.println(p2.count);
System.out.println(p2.age);
}
}
我们new了两个对象p1和p2,我们age++和count++由前面的知识可知道,不赋值的整形应该是默认为0,那我们打印的age和count应该都是1,而不同对象的age和count也应该是单独的、互补影响的,所以4个打印都应该是1啊,同样验证,普通成员变量age符合我们上面所说的要求,p1.age和p2.age打印的都是1。但是问题出现了,p2的count(静态成员变量)打印的是2
count默认是0,却打印了2,就好像p1.count和p2.count进行++操作的时候是对同一个内容进行操作一样,这不符合逻辑啊?但事实就是这样哈哈哈
静态成员变量又称类变量,被static修饰过后,count是被放到方法区中(不是堆区!) ps:方法区会存储对应类的字节码文件(.class文件),还会存储静态的成员变量 静态成员变量不是对象的,它是类的,且在方法区中只有一个,不像对象,每一个对象一个对应的成员变量。
到这里也解释了,为什么我们用p1.count++和p2.count++会是对同一空间同一内容进行操作(count只有一个)。而p1.age,和p2.age是两个不同空间的不同的内容。
我们上面代码new p1 和new p2来调用count都是没有意义的,你可以直接使用类名Person来调用count,也间接的节约了创建对象所需的空间
static修饰的静态成员方法 直接用类就可以调用,其他的和普通成员方法没区别
class Person{
public static void xiao() {
System.out.println("haha");
}
}
public static void main(String[] args) {
Person.xiao();
}
注意:静态的成员变量是不可以在普通方法中定义的
public static void m() {
static int a=1;
}
普通方法里能调用静态方法
public static void hello() {
System.out.println("你好");
}
public void print() {
hello();
}
静态方法里不能调用普通方法
class Person{
public String name;
public int age;
public static void staticFunc() {
print();
}
public void print() {
System.out.println("姓名"+name+"年龄"+age);
}
}
原因很简单,静态方法是不依赖对象的,我们本是可以通过类名进行调用,但是普通成员变量是依赖对象的,你如果调用了staticFunc里的print,print里面的name和age哪里来的对象呢?
当然了,如果你非要抬杠,我就要在静态方法里调用普通方法怎么办,如下
class Person{
public String name;
public int age;
public static void staticFunc() {
Person p=new Person();
person.print();
}
public void print() {
System.out.println("姓名"+name+"年龄"+age);
}
}
再举一个相似的例子:
public class TestDemo {
public static void func1() {
}
public void func2() {
}
public static void main(String[] args) {
func1();
TestDemo test=new TestDemo();
test.func2();
}
}
综上:静态方法可以直接通过类名调用,普通方法则需要new一个对象 final修饰的常量/静态常量
class Test{
public int a;
public static int count;
public final int size=1;
public final static int c=99;
}
一个对象存储在哪里和final无关,还是取决于是否有static 最后:注意——static定义的东西只能在类里面定义,不可以在方法里定义
小知识:main函数是不是静态static的都可以,取决于JVM的设计逻辑
2.4小结
1.静态成员变量的访问方式是通过类名.静态成员属性/方法,只要是静态的就是不依赖于对象的,因为你普通成员变量需要通过访问对象来实现,但是静态的直接通过类就可以进行访问了 2.普通成员方法调用需要对象的引用,但是static的静态成员方法可以直接通过类名来调用 3.静态的成员变量是不可以在方法中定义的(因为它是类变量) 4.普通方法里可以调用静态方法 5.静态方法里不可以调用普通方法 6.静态方法可以直接通过类名调用,普通方法则需要new一个对象
三、封装
3.1private实现封装
private/public两个关键字表示“访问权限控制” 1.被public修饰的成员变量或成员方法,可以直接被类的调用者使用。 2.被private修饰的成员变量或成员方法,不能被类的调用者使用
class Test{
public String name;
}
class Name{
private String name;
}
public class TestDemo {
public static void main(String[] args) {
Test t=new Test();
t.name="abc";
Name n=new Name();
n.name="abc";
}
}
被类Name中的name被private修饰后的,只能在当前的类中进行访问,打个不恰当的比方,现在疫情封城了,你只能在你所在的城市里活动,不允许出城。private就相当于封城令,而被修饰的属性/方法就是我们人,当前类就是我们当前的城市。
那说了这么多,我们为什么要用private呢? 1.我们用了private后,它修饰的属性或方法(你不想让别人拿到修改的东西)就会更加安全。 2.如果不用private,比如我之前的类Name中我们是用public String name; 如果哪天有人给我把类里面的name改成了myname,那后面很多程序用的时候是用的对象名.name,你现在name没了啊,难道还要一个一个去往下改吗?这显然不现实。用了private之后用户只需要调用你公开的方法(3.2的getter和setter方法)即可,你在类里面把name改成什么都可以。
注意事项: 1.private不光能修饰字段,也能修饰方法 2.通常情况下我们会把字段设为private属性,但是方法是否需要设计为public,就需要视情况而定,一般我们希望一个类只提供“必要的”public方法,而不是所有方法都无脑设为public
3.2getter和setter方法
我们3.1用private封装了属性或方法,那这个时候肯定会有小伙伴问,那如果我真的想要使用那个被封装的属性或方法呢?也很简单,代码如下:
class Name{
private String name;
public String getName() {
return name;
}
public void setName(String myName){
name=myName;
}
}
public class TestDemo {
public static void main(String[] args) {
Test t=new Test();
t.name="abc";
Name n=new Name();
n.setName("xiaoMing");
String x=n.getName();
System.out.println(x);
}
}
打印效果如下: 注意事项: 1.getName即为getter方法,表示获取这个成员的值。 2.setName即为setter方法,表示设置这个成员的值。
四、构造方法
4.1基本语法
构造方法是一种特殊方法,方法名和类名是相同的,且没有返回值,它使用关键字new实例化新对象时会被自动调用,用于完成初始化操作。 new执行过程: 1.为对象分配空间 2.调用对象的合适的构造方法 (合适就意味着构造方法不唯一) 语法规则: 1.方法名称必须与类名称相同 2.构造方法没有返回值类型声明 3.每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造) 示例如下:
class people{
public people(){
System.out.println("people()不带参数的构造方法");
}
}
那我们怎么调用这个构造方法呢?
public static void main(String[] args) {
people p=new people();
}
new一个对象直接执行代码即可,打印效果如下: 再来看看带参数的构造方法及其使用方式
class people{
public String name;
public people(){
System.out.println("people()不带参数的构造方法");
}
public people(String name){
this.name=name;
System.out.println("people(String)带String参数的构造方法");
}
}
public class TestDemo {
public static void main(String[] args) {
people p=new people("xiaoHei");
}
}
new对象的时候把相应构造方法需要的参数放进去即可完成调用,打印效果如下:
冷知识:如果你原先的类里没有任何构造方法,那么编译器会默认生成一个不带有参数的构造函数。:
class people{
}
public class TestDemo {
public static void main(String[] args) {
people p=new people();
}
}
你执行上面的代码也不会报错,系统会默认为你生成如下代码
class people{
public people(){
}
}
注意事项: 1.如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。 2.若类中定义了构造方法,则默认的无参构造将不再生成。 3.构造方法支持重载,规则和普通方法的重载一致。
4.2this关键字
我们来回顾一下3.1的代码
class Name{
private String name;
public void setName(String myName){
name=myName;
}
}
有时候我们可能不小心把形参写成了成员名一样
class Name{
private String name;
public void setName(String name){
name=name;
}
}
但上述的赋值方法是默认形参赋给形参,你并没有真正实现成员name的赋值,那如果我们写的函数形参就是和成员变量名一样呢?我们用this
class Name{
private String name;
public void setName(String name){
this.name=name;
}
}
注意事项: 1.this.data表示调用当前对象的属性 2.this.func()表示调用当前对象的方法 3.this()调用当前对象的其他构造方法——this()只能存在于构造方法中 关于3,解释如下:
class people{
public String name;
public people(){
this("hh");
System.out.println("people()不带参数的构造方法");
}
public people(String name){
this.name=name;
System.out.println("people(String)带String参数的构造方法");
}
}
public class TestDemo {
public static void main(String[] args) {
people p=new people();
}
}
我们从main函数进去,new了一个对象,开始调用不带参数的构造方法,不带参数的构造方法里有一个this(),this()表示调用当前对象的其他构造方法,也就说这里的this(“hh”)=people(“hh”),也就是进入了另一个构造方法 public people(String name),然后打印"people(String)带String参数的构造方法",出 public people(String name),回到public people(),打印"people()不带参数的构造方法" 一般的,我们会在当前对象属性/方法前加this.因为你加上一定没错,不加可能当前对象属性/方法会与形参相同导致错误。简言之,加上一定没错,不加可能有错。
五、认识代码块
字段的初始化方法有: 1.就地初始化 2.使用构造方法初始化 3.使用代码块初始化 前面两种我们已经学习过了,接下来我们介绍第三种方式,使用代码块初始化
5.1什么是代码块
使用{ }定义的一段代码 根据代码块定义的位置及关键字,又可分为以下四种: 1.普通代码块 2.构造代码块 3.静态块 4.同步代码块(后续讲解多线程部分继续学习)
5.2普通代码块
定义在方法中的代码块,直接用{ }定义,示例如下:
{
代码内容
}
5.3构造代码块
也叫实例代码块,示例如下:
class person{
private String name;
private int age;
private String sex;
}
{
this.name="bit";
this.age=12;
this.sex="m";
}
实例代码块优先于构造函数运行。
5.4静态代码块
使用static定义的代码块,一般用于初始化静态成员属性。 示例如下:
static{
count=10;
}
5.5引申
class people{
public String name;
public people(){
System.out.println("people()不带参数的构造方法");
}
public people(String name){
this.name=name;
System.out.println("people(String)带String参数的构造方法");
}
{
System.out.println("实例代码块");
}
static{
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
people p=new people();
}
}
我们由构造方法那块知识知道,我们new了一个不带参数的对象然后直接运行,一定会得到不带参数的构造方法里面的一些东西,然后我们people这个类里面代码块的顺序是构造方法->实例代码块->静态代码块,但我们上面这段代码实际运行情况并不是这样 我们是优先运行了静态代码块,然后是实例代码块和构造方法。不管静态、实例、构造代码块在类中的顺序,静态代码块一定是先被打印,其次是实例代码块,最后是构造方法,如果大家都是相同类型(比如同是静态)的,这时才看的是代码顺序。 我们再细化看一下实例代码块和静态代码块的区别
class people{
public String name;
public people(){
System.out.println("people()不带参数的构造方法");
}
public people(String name){
this.name=name;
System.out.println("people(String)带String参数的构造方法");
}
{
System.out.println("实例代码块");
}
static{
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
people p1=new people();
System.out.println("===============");
people p2=new people();
}
}
我们new了两个对象,但我们静态代码块永远只执行一次,剩下的实例代码块和构造方法均执行两次。 我们再来测试一下,不new对象的运行效果
class people{
public static int count;
public String name;
public people(){
System.out.println("people()不带参数的构造方法");
}
public people(String name){
this.name=name;
System.out.println("people(String)带String参数的构造方法");
}
{
System.out.println("实例代码块");
}
static{
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
System.out.println(people.count);
System.out.println(people.count);
}
}
静态代码块不需要实例化对象也可以运行,但是不管你执行几次,静态代码块只会执行一次。 静态代码块本质上来说:是初始化静态的东西的,它是不依赖于对象的
六、一些补充
6.1匿名对象
匿名只是表示没有名字的对象。 1.没有引用的对象成为匿名对象 2.匿名对象只能在创建对象时使用 3.如果一个对象只是用一次,后面不需要用了,可以考虑使用匿名对象。
class people{
public void eat(){
System.out.println("正在吃东西");
}
public void drink(){
System.out.println("正在喝东西");
}
}
public class TestDemo {
public static void main(String[] args) {
new people().eat();
new people().drink();
}
}
上述这个代码,我们new了一个对象却没有把它赋给任何值,再用这个new出来的对象去调用eat函数。这种操作方法我们不需要名字,可以直接使用,就叫作匿名对象。但是有个缺点,就是你如果用匿名对象,每用一个需要对象的函数都要new一个匿名对象,比如我们上面调用两个函数eat和drink就new了两个对象的空间,比较浪费空间。
七、小结
1.一个类可以产生无数的对象,类就是模板,对象就是具体的实例。 2.类中定义的属性,大概可分为几类:类属性,对象属性。其中被static修饰的数据类型称为类属性,static修饰的方法称为类方法,特点是不依赖于对象,我们只需要通过类名就可以调用其属性或者方法。 3.静态代码块优先实例代码块执行,实例代码块优先构造函数执行。 4.this关键字代表的是当前对象的引用,不是当前对象。
|