面向过程:注重过程,在整个过程中所涉及的行为,就是功能。
面向对象:注重对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来。
类:一组具有相同特征的对象的抽象,对象就是这一类具体化的一个实例,类中定义了所有该类对象所共同具备的属性和方法。
类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。
所有类的对象都是引用数据类型,对于引用类型来说,默认值为 null 。Java 使用关键字 class 来声明类。
基本语法
// 创建类
class{field;//成员属性method();//成员方法
}
// 实例化对象<对象名> &#61; new (); class 为定义类的关键字&#xff0c;ClassName 为类的名字&#xff0c;{} 中为类的主体。
类中的元素称为&#xff1a;成员属性。
类中的函数称为&#xff1a;成员方法。
类的实例化
//代码示例
class Person {public int age; //成员属性 实例变量public String name;public String sex;public void eat() { //成员方法System.out.println("吃饭!");}public void sleep() {System.out.println("睡觉!");}
}public class Main{public static void main(String[] args) {Person person &#61; new Person(); //通过new实例化对象person.eat(); //成员方法调用需要通过对象的引用调用person.sleep();//产生对象 实例化对象Person person2 &#61; new Person();Person person3 &#61; new Person();}
}
//输出结果
吃饭!
睡觉!注意事项
1. new 关键字用于创建一个对象的实例。
2. 使用 . 来访问对象中的属性和方法。
3. 同一个类可以创建对个实例。
类的成员可以包含以下&#xff1a;字段、方法、代码块、内部类和接口等。
在类中&#xff0c;但是方法外部定义的变量。这样的变量我们称为 "字段" 或 "属性" 或 "成员变量" (三种称呼均可)。用于描述一个类中包含哪些数据。
class Person {public String name; // 字段public int age; // 字段
}
class Test {public static void main(String[] args) {Person person &#61; new Person();System.out.println(person.name);System.out.println(person.age);}
}
// 执行结果
null
0注意事项
1. 使用 . 访问对象的字段。
2. "访问" 既包含读&#xff0c;也包含写。
3. 对于一个对象的字段如果没有显式设置初始值&#xff0c;那么会被设置一个默认的初值。默认值规则
1. 对于各种数字类型&#xff0c;默认值为 0。
2. 对于 boolean 类型&#xff0c;默认值为 false。
3. 对于引用类型(String&#xff0c;Array&#xff0c;以及自定制类)&#xff0c;默认值为 null。
认识 null
null 在 Java 中为 "空引用"&#xff0c;表示不引用任何对象。类似于 C 语言中的空指针。如果对 null 进行 . 操作就会引发异常。
如果报错 NullPointerException ->空指针异常&#xff0c;一定使用了一个值为 null 的引用去访问成员属性或者成员方法了。&#xff08;null 访问 static 属性不报错&#xff09;
class Person {public String name; //成员属性public int age; //成员属性
}
class Test {public static void main(String[] args) {Person person &#61; new Person();System.out.println(person.name.length()); // 获取字符串长度}
}
// 执行结果
Exception in thread "main" java.lang.NullPointerException
字段就地初始化
不使用默认值&#xff0c;而是显式设定初值的操作。
class Person {public String name &#61; "张三"; //赋初值public int age &#61; 18; //赋初值}class Test {public static void main(String[] args) {Person person &#61; new Person();System.out.println(person.name);System.out.println(person.age);}
}
// 执行结果
张三
18
方法&#xff1a;用于描述一个对象的行为。
class Person {public int age &#61; 18;public String name &#61; "张三";public void show() {System.out.println("我叫" &#43; name &#43; ", 今年" &#43; age &#43; "岁");}
}class Test {public static void main(String[] args) {Person person &#61; new Person();person.show(); //调用方法}
}
// 执行结果
我叫张三, 今年18岁此处 show 成员方法是和 person 实例对象相关联的。如果创建了其他实例&#xff0c;那么 show 的行为就会发生变化。
Person person2 &#61; new Person();
person2.name &#61; "李四";
person2.age &#61; 20;
person2.show(); //其他实例调用方法
// 执行结果
我叫李四, 今年20岁
Java静态属性和类相关&#xff0c;和具体的实例对象无关。
当一个实例变量被 static 关键字修饰&#xff0c;他就表示类的属性&#xff0c;该类的所有对象共享这个属性&#xff0c;所有对象的属性值都一样。
static 修饰的属性在 JVM 方法区中存储&#xff0c;所有该类对象共享此属性。
class Person{String name; // 成员变量&#xff0c;实例变量必须通过该类的对象来访问int age; // 人这个属性中&#xff0c;需要有单独个体&#xff0c;才能得出该个体的name、agestatic String country; // 很多对象在堆中共有的成员属性countryvoid show() { // 成员方法&#xff0c;实例方法&#xff0c;也是必须通过对象来访问System.out.println("name &#61; " &#43; name &#43;",age &#61; " &#43; age &#43; ",country &#61; " &#43; country);}
}public class Main{public static void main(String[] args) {Person per1 &#61; new Person();per1.name &#61; "张三";per1.age &#61; 20;per1.show();Person per2 &#61; new Person();per2.name &#61; "李四";per2.age &#61; 18;per2.show();}
}
//输出结果
name &#61; 张三,age &#61; 20,country &#61; 中国
name &#61; 李四,age &#61; 18,country &#61; 中国
class Person{static String country &#61; "中国"; //很多对象在堆中共有的成员属性country}
}public class Main{public static void main(String[] args) {Person per1 &#61; new Person();System.out.println(Person.country); //用 类 访问static成员属性System.out.println(per1.country); //用 对象 访问static成员属性}
}
//输出结果
中国
中国问题1&#xff1a;Java中能否在一个方法内部&#xff0c;定义一个 static 变量&#xff1f;
答&#xff1a;不能&#xff0c;方法中定义的变量全部都是局部变量&#xff0c;局部变量在栈中存储&#xff0c;而static 变量在方法区&#xff0c;属性不可能同时存在于栈与方法区中。静态 main 方法中同样不能定义static 变量。
问题2&#xff1a;定义Person per2 &#61; null&#xff1b;
执行 per2.country 是否报错"空指针异常";
public static void main(String[] args) {Person per2 &#61; null;System.out.println(per2.country);
}
class Person {static String country &#61; "中国";
}
//输出结果
中国答&#xff1a;可以&#xff0c;static 属性称为类属性&#xff0c;通过类名称直接访问。故没有对象也可以调用&#xff08;包含类的null引用&#xff09;&#xff0c;而不会出现 NullPointerException ->空指针异常报错。
class Person {//成员常量&#xff0c;都在堆中存储&#xff0c;必须在定义时赋值final int age &#61; 18;//静态变量&#xff0c;在方法区中存储&#xff0c;所有Person的对象共享这个country属性static String country &#61; "中国";
}age 这个属性为成员常量&#xff0c;在类定义的时候就已赋值为18了。Person的所有对象都有age属性&#xff0c;且值都是18。把他定义为 static final &#xff0c;可以节省空间&#xff0c;并且所有Person对象共享这个属性&#xff0c;全局唯一。
故在类中定义常量&#xff0c;一般使用全局常量&#xff0c;用 static final 共同修饰。
所有单词全部大写&#xff0c;多个单词使用下划线分隔。
如&#xff0c;static final String STUDENT_SCHOOL &#61; "清华大学"&#xff1b;
总结
- static 变量称为类属性&#xff0c;在方法区中存储&#xff0c;该类的所有对象共享此变量。
- 若在类中定义了常量(定义时赋值)&#xff0c;一般我们使用 static 和 final 共同修饰变成全局常量。
- 要使用类属性&#xff0c;我们通常直接通过类名称 . 属性名称&#xff0c;不推荐使用对象来调用类属性&#xff0c;这样不规范。
staic修饰的方法&#xff0c;也是通过类名称直接访问的方法&#xff0c;没有对象也能访问。
类方法&#xff0c;如主方法
工具方法&#xff0c;如Arrays.sort(int[])、Arrays.copyOf(int[])
都是Arrays对外提供的操作数组的方法&#xff0c;将其设计为 static 方法
问题1&#xff1a;为何主方法是 static 方法&#xff1f;
答&#xff1a;主方法是程序的入口。如果主方法是成员方法&#xff0c;则需要 new 出对象调用&#xff0c;但没有程序入口&#xff0c;就产生不了对象。
程序从主方法开始运行&#xff0c;主方法要能够调用其他方法&#xff0c;所以设计为 static &#xff0c;直接调用而不用产生对象。
问题2&#xff1a;静态方法能否访问成员变量、成员方法&#xff1f;
答&#xff1a;不能&#xff0c;成员方法、成员变量必须通过对象来调用。 static 里面没有该类对象&#xff0c;所以无法调用。
问题3&#xff1a;成员方法能否访问静态变量、静态方法&#xff1f;
答&#xff1a;可以&#xff0c;有对象才能调用成员方法&#xff0c;static 没对象都能调用&#xff0c;更何况有对象&#xff0c;那就更能调用了。
问题4&#xff1a;外部类能否使用 static 关键字修饰&#xff1f;
答&#xff1a;不能&#xff0c;编译出错。类定义出来就是要产生对象的&#xff0c;static 类没对象&#xff0c;就能调用。
总结
1. 在静态方法中只能调用静态方法或者静态属性&#xff0c;static家族之间可以相互调用。从中不能直接调用成员方法和成员属性&#xff0c;必须通过对象来调用。
2. 在成员方法中既可以调用成员方法&#xff0c;也可调用静态方法(此时都已经产生了该类对象&#xff0c;一定是可以访问静态域的)。
保护性和易用性
在Java中&#xff0c;所谓的权限修饰符&#xff0c;指的是修饰的属性、方法、类&#xff0c;到底可见的范围有多大。其中一共有四大访问修饰符&#xff0c;可见的范围又小到大依次为&#xff1a;
private
private 私有的&#xff0c;被private修饰的属性和方法&#xff0c;只在当前类的内部可见&#xff0c;出了类就对外部就完全隐藏了&#xff0c;外部不知道有其存在。
public 公共的&#xff0c;公开的被public修饰的属性和方法&#xff0c;在当前程序(项目)中都是可见的&#xff0c;都是可以使用的。
类比现实
对于银行卡这个类来说&#xff0c;银行卡有卡号&#xff0c;余额&#xff0c;密码这三个属性。如果这三个属性直接暴露在外部&#xff0c;显然不安全&#xff0c;不能让这些属性通过对象直接就访问了。
想在类的外部去使用这些私有属性&#xff0c;需要使用类提供的 getter (取值)和 setter (修改值)。
// 公共访问权限&#xff0c;主类&#xff0c;这个类在当前项目中都是可见的
public class PrivateTest {public static void main(String[] args) {Bank bank &#61; new Bank();// 当password属性被private之后&#xff0c;对于这个属性就是一个保护// 类的外部要想使用这个属性&#xff0c;必须按照我的规则去使用(getter和setter)bank.setPassword();System.out.print("修改后的密码为:");System.out.println(bank.getPassword());}
}// 银行类,缺省修饰符&#xff0c;包访问权限
class Bank {private int cardNum; // 卡号private double sal; // 余额private String password &#61; "123456"; // 密码// alt &#43; insert 快速生成getter和setter方法// get&#43;属性名称 &#61; 方法命名public int getCardNum() { //取值return cardNum;}public double getSal() { //取值return sal;}public String getPassword() { //取值return password;}public void setPassword() {Scanner scanner &#61; new Scanner(System.in);int count &#61; 0;// 验证当前密码是否正确才能修改while (true) {System.out.println("请输入您现在的旧密码:");String oldPass &#61; scanner.nextLine();count &#43;&#43;;// 所有引用类型的对象比较使用equals方法if (oldPass.equals(password)) {// 密码输入正确&#xff0c;修改密码System.out.println("密码正确&#xff0c;正在改密码");System.out.println("请输入您的新密码&#xff1a;");String newPass &#61; scanner.nextLine();password &#61; newPass;System.out.println("密码修改成功!");break;} else {// 输入密码有误System.out.println("密码错误&#xff0c;请查证后再试");if (count &#61;&#61; 3) {System.out.println("尝试次数过多&#xff0c;银行卡已经锁定");break;}}}}
}
问题1&#xff1a;private 能否修饰外部类&#xff1f;
答&#xff1a;不能&#xff0c;类定义出来就是为了产生对象&#xff0c;让外部使用。用 private 封装&#xff0c;在外面就看不到了&#xff0c;从而不能使用对象。
构造方法是类中非常特殊的一类方法&#xff0c;使用关键字 new 实例化对象时&#xff0c;实际上就调用的是该类的构造方法。构造方法的作用就是产生对象。
使用关键字 new 产生一个对象时&#xff0c;大致分为以下两步&#xff1a;
1.为对象在堆中分配空间
2.调用对象的构造方法为对象成员变量赋值
构造方法语法规则&#xff1a;
1. 方法名称与类名称完全相同。
2. 构造方法没有返回值声明(无void)。
3. 一个类中至少存在一个构造方法&#xff0c;若没有显示定义&#xff0c;编译器会生成—个默认的无参构造。
定义构造方法
public class TestClass {public static void main(String[] args) {Person per &#61; new Person();}
}class Person {private String name;private int age;public Person() { //构造方法的定义System.out.println("Person的无参构造");}
}
//输出结果
Person的无参构造若没有定义构造方法&#xff0c;编译器会自动生成一个。
当类中自定义了构造方法&#xff0c;默认的无参构造就不再生成。
构造方法在内存空间赋值
构造方法的重载
构造方法是为了类中的成员变量赋值的&#xff0c;此时的重载只可能是参数的个数不同。
&#xff08;成员变量的类型在类定义时就指定好了&#xff0c;只是初始化的变量个数不同。&#xff09;
public class TestClass {public static void main(String[] args) {Person per1 &#61; new Person();Person per2 &#61; new Person("小明");Person per3 &#61; new Person("小明", 18);// 这三个对象构造方法都已经调用结束&#xff0c;初始化完成}
}class Person {private String name;private int age;private String sex;public Person() { //无参构造方法的定义//mame &#61; null;age &#61; 0;sex &#61; null; //首行赋默认值System.out.println("Person的无参构造");}public Person(String n) { //传一个参数//mame &#61; null;age &#61; 0;sex &#61; null; //首行赋默认值name &#61; n;System.out.println("name &#61; " &#43; name);System.out.println("Person的一个参数的有参构造");}public Person(String n, int a) { //传两个参数//mame &#61; null;age &#61; 0;sex &#61; null; //首行赋默认值name &#61; n;age &#61; a;System.out.println("name &#61; " &#43; name &#43; ",age &#61; " &#43; age);System.out.println("Person的两个参数的有参构造");}
}
//输出结果
Person的无参构造
name &#61; 小明
Person的一个参数的有参构造
name &#61; 小明,age &#61; 18
Person的两个参数的有参构造成员变量定义时赋初值
成员变量只有在产生对象时&#xff0c;才会在堆中分配空间&#xff0c;然后调用构造方法赋值。
问题&#xff1a;此处对象 per1 能否调用构造方法 Person &#xff1f;
答&#xff1a;不能&#xff0c;报错 java&#xff1a;找不到符号。
符号&#xff1a;方法 Person()
位置&#xff1a;类型为Person的变量 per1自己调用自己的构造方法&#xff0c;JVM 产生对象时调用构造方法&#xff0c;对象实例化结束&#xff0c;无法在程序中手动调用构造方法再次实例化对象。
this 关键字表示当前对象的引用
public class ThisTest {public static void main(String[] args) {Student student &#61; new Student("小明", 20, "男");student.show();}
}class Student {private String name; private int age;private String sex;public Student(String name, int age, String sex) {name &#61; name; //就近匹配age &#61; age;sex &#61; sex;System.out.println("Student类的有参构造");}public void show() {System.out.println("name &#61; " &#43; name &#43; ",age &#61; " &#43; age &#43; ",sex &#61; " &#43; sex);}
}
//输出结果
Student类的有参构造
name &#61; null,age &#61; 0,sex &#61; null程序的设计理念&#xff0c;就近匹配原则&#xff0c;编译器会找到最近的相同名称的变量在哪。上述情况&#xff0c;形参自己等于了自己&#xff0c;对类中的成员变量没有任何影响。
如何打破就近匹配原则&#xff0c;从类中找同名变量&#xff1f;——>使用 this 关键字。形参的值给了成员变量。
//使用 this 关键字&#xff0c;改正上述问题
public Student(String name, int age, String sex) {this.name &#61; name;this.age &#61; age;this.sex &#61; sex;System.out.println("Student类的有参构造");}
//输出结果
Student类的有参构造
name &#61; 小明,age &#61; 20,sex &#61; 男
public class ThisTest {public static void main(String[] args) {Student student &#61; new Student();student.fun();}
}class Student {private String name;private int age;private String sex;public void test() {System.out.println("Student类的test成员方法");}public void fun() {//此处没有用对象调用 test();test();System.out.println("Student类的fun成员方法");}
}
//输出结果
Student类的test成员方法
Student类的fun成员方法此处 test() 未使用对象却依旧可以调用&#xff0c;原因是编译器编译后默认加上 this &#xff0c;使其变成当前对象的引用 this.test() 。
若不同参数的构造方法之间出现了重复的调用&#xff0c;可以使用this(参数)调用其他的构造方法。
public Student() {System.out.println("********************");}public Student(String name) {//调用无参构造this();this.name &#61; name;}public Student(String name, int age) {this(name);this.age &#61; age;}