目录
一、类和对象的基本概念
二、类与对象的定义与使用
1.创建类的语法:
2. 创建具体的对象:
3.范例(创建一个Person 类的对象)
三、static关键字
(一)static修饰属性(类属性、类变量)
(二)static修饰方法(类方法、工具方法)
(三)static修饰代码块(静态代码块)
(四)static修饰内部类(静态内部类)
四、面向对象的特性
五、构造方法
六、this 关键字(表示当前对象的引用)
七、代码块
在Java中一切皆对象,一切都围绕对象进行,找对象、建对象,用对象等
类:把具有相同属性和行为的一类对象抽象为类。类是抽象概念,如人类、犬类等,无法具体到每个实体。
对象:某个类的一个实体,当有了对象后,这些属性便有了属性值,行为也就有了相应的意义。
类是描述某一对象的统称,对象是这个类的一个实例而已。有类之后就能根据这个类来产生具体的对象。一类对象所具备的共同属性和行为(方法)都在类中定义。
class 类名称 {
成员变量/ 实例变量;
成员方法;
}
类名称 引用名称 = new 类名称()
Person per = new Person();
这个对象的引用 对象(在堆中储存)
(相当于给对象起了个名字)(所有类的对象都是引用数据类型)
public class Test {
public static void main(String[] args) {
//创建一个实例化对象
Person per1 = new Person();
//通过对象来调用实例变量、成员方法
per1.name = "小韩";
per1.age = 18;
per1.sex = "女";
per1.print();
Person per2 = new Person();
per2.print();
}
}
class Person{
//成员变量(实例变量),在堆中的每个对象中存储,通过对象调用
String name;//默认值为null
int age;//默认值为0
String sex;//默认值为null
//成员方法(实例方法),在JVM的方法区中存储,通过对象调用
void eat(String food){
System.out.println(name+"正在吃"+food);
}
void print(){
System.out.println("name:"+name+", age:"+age+", sex:"+sex);
}
}
输出结果:
注意事项:
//sex的默认值为null
//sex.length()
System.out.println(per2.sex.length());
1.当一个实例变量被static关键字修饰后,它就表示类的属性,该类的所有对象共享此属性,且对象的属性值相同。static修饰的属性在JVM的方法区中存储。
2.static修饰的属性,直接通过类名称就可以访问,无须通过对象。
public class staticTest {
public static void main(String[] args) {
Person per1 = new Person();
Person per2 = new Person();
per1.name = "小韩";
per1.age = 18;
per1.print();
per2.print();
Person.country="日本";
per1.print();
per2.print();
System.out.println(Person.country);
}
}
class Person {
//实例变量,成员方法,必须通过该类的对象来访问
String name;
int age;
String sex;
//静态成员变量,不属于对象,属于类,保存在方法区中
// 调用时通过 类名称.country来进行访问
static String country = "中国";
void print(){
System.out.println("name:"+name+", age:"+age+", country:"+country);
}
}
输出结果:
注意:
Person per = null;
System.out.println(per.country);//相当于Person.country
并不会报空指针异常:static属性称为类属性,通过类名称直接访问,此时没有对象也能调用(包含该类的null引用)
3.final 和 static 的区别
class Person {
final int age = 18;//成员常量,在堆中存储,必须在定义时就赋值
static String country = "中国"//静态变量,在方法区中存储,所有Person类的对象共享
}
若在类中定义了一个常量,通常情况下都会把static 和 final 共同使用,称为类的常量
(因为age属于成员常量,Person类的所有对象都有age这个属性,且值都是18——>天然的共享概念,将它定义为static final,所有Person类的对象共享这个属性,全局唯一。(既节省空间,有对应共享语义))
全局常量的命名规则:所有单词全部大写,多个单词使用下划线分隔
static final String STUDENT_SCHOOL ="清华大学";
问题1:能否在方法中定义一个static变量?
不能。在方法中定义的变量是局部变量,在栈中存储,而 static变量是在方法区中存储,若要在方法中定义一个static变量就会产生矛盾,因为一个变量不可能既在栈中存储,又在方法区中存储。
static修饰的方法通过类名称直接访问方法,没有对象也可以访问。
问题2:为什么static 方法是一个静态方法?
因为主方法是程序的入口,在进入主方法前没有对象, 如果主方法是一个成员方法,需要通过对象调用,就会产生矛盾。要使程序开始执行,只有通过类名称直接调用静态方法,无须产生对象。
问题3:静态方法能否访问成员变量和成员方法?
不能。 静态方法可以通过类名称直接访问,此类中没有对象也可以访问;成员方法和成员变量必须要通过类中的对象来访问。没有对象的方法去调用必须通过对象访问的变量和方法,二者之间矛盾。
问题4:成员方法能否访问静态变量和静态方法?
可以。 必须通过对象访问的方法去调用不需要对象就可以访问的变量和方法,逻辑通过
static方法只能调用静态变量和静态方法等,static家族的成员可以相互调用(都属于静态域)
问题5:普通的类能否使用static关键字修饰(不是内部类)?
类定义出来是要产生对象的,用static关键字修饰一个类,这个类不需要对象就能调用,矛盾。
面向对象一共有三大特性:封装、继承和多态(本篇博客主要讨论封装性)
封装:保护性和易用性
封装有很多表现形式,private实现属性和方法的封装只是其中一种。
权限修饰符:在Java中,权限修饰符指的是所修饰的属性、方法或者类可见的范围有多大。
一共有四大访问修饰修饰符,可见的范围由小到大依次为 :
private(私有的):被private 修饰的属性和方法,只在当前类可见,出了类的{ },对外就完全隐藏了,外部不知道有其存在。
default(不需要写这个关键字,什么权限也没有(包访问权限))
protected(继承访问权限)
public(公共的、公开的):被public 修饰的,在当前程序(项目)中都是可见并且可以使用的。
//公共访问权限,主类
public class privateTest {
public static void main(String[] args) {
Bank bank = new Bank();
bank.setPassword();
System.out.println("修改后的密码为:");
System.out.println(bank.getPassword());
System.out.print("银行卡号为:");
System.out.println(bank.getCardNum());
System.out.print("银行卡余额为:");
System.out.println(bank.getBalance());
}
}
//缺省修饰符,包访问权限
class Bank{
//私有属性,只在Bank这个类内部可见
private int cardNum;//卡号,只可取
private double balance;//余额,只可取
private String password = "123456";//密码,既可取也可改
//要在类的外部去使用这些私有属性,需要使用类提供的getter()和setter()方法
//alt + insert 快速生成getter()和setter()方法
//shift+A全选
//get + 属性名称 = 方法命名
public int getCardNum() {
return cardNum;
}
public double getBalance() {
return balance;
}
public String getPassword() {
return password;
}
//设置新密码
public void setPassword() {
//验证旧密码(安全性)
Scanner scan = new Scanner(System.in);
int count = 0;
while(true){
System.out.println("请输入您的旧密码:");
String oldPass = scan.nextLine();
count ++;
if (oldPass.equals(password)) {
System.out.println("验证成功,请输入您的新密码:");
String newPass = scan.nextLine();
password = newPass;
System.out.println("密码修改成功");
break;
}else{
System.out.println("密码错误,请查证后再试!");
if(count == 3){
System.out.println("验证次数过多,银行卡已锁定");
break;
}
}
}
}
}
问题6: private 关键字能否修饰一个类(外部类)?
不能。定义类是为了产生对象,让外部使用的。若用 private 关键字封装此类,则外部根本不知道此类的存在,更不用提使用对象了,矛盾。
1、构造方法:构造方法是类中非常特殊的一类方法,使用关键字new 实例化对象时实际上调用的就是该类的构造方法。
2.构造方法的作用就是产生对象
3.使用new关键字产生一个对象时,大致分为以下两步:
(1)为对象在堆中分配空间(空间大小由该类中成员变量的属性决定)
(2)调用对象的构造方法为对象成员变量赋值(当构造方法调用结束后,该对象初始化完成)
4.构造方法的语法规则
(1)方法名称与类名称完全相同
(2)构造方法没有返回值声明(不是void)
(3)一个类中至少存在一个构造方法,若没有显示定义,编译器会生成一个默认的无参构造。
public class Test {
public static void main(String[] args) {
//当创建一个对象时,默认调用该类的构造方法
Person person = new Person();
}
}
class Person{
String name;
int age;
String sex;
//构造方法名称与类名称完全相同
//没有返回值声明
public Person(){
System.out.println("Person的构造方法");
}
}
若没有定义构造方法,编译器会生成一个默认的无参构造
public class Test {
public static void main(String[] args) {
//当构造对象时,默认调用该类的构造方法
Person person = new Person();
}
}
class Person{
String name;
int age;
String sex;
}
5.当类中自定义了构造方法,默认的无参构造就不再生成。
public class Test {
public static void main(String[] args) {
//当构造对象时,默认调用该类的构造方法
Person person = new Person();
}
}
class Person{
String name;
int age;
String sex;
public Person(String n){
name = n ;
System.out.println("Person类的有参构造");
}
}
编译出错:
6、构造方法的重载
构造方法是为了类中的成员变量赋值的,此时的重载只可能是参数的个数不同。
public class Test {
public static void main(String[] args) {
//当构造对象时,默认调用该类的构造方法
Person person = new Person();
Person person1 = new Person("小韩");
Person person2 = new Person("小韩",18);
Person person3 = new Person("小韩",18,"女");
}
}
class Person{
String name;
int age;
String sex;
public Person(){
//构造方法首行name = null,age = 0;sex = null(不用写)
System.out.println("Person类的无参构造");
}
public Person(String n){
//首行name = null,age = 0;sex = null;
name = n ;
System.out.println("name:"+name);
System.out.println("Person类的一个参数的有参构造");
}
public Person(String n,int a){
name = n ;
age = a;
System.out.println("name:"+name+", age:"+ age );
System.out.println("Person类的两个参数的有参构造");
}
public Person(String n,int a,String s){
name = n ;
age = a;
sex = s;
System.out.println("name:"+name+", age:"+ age +", sex :"+sex);
System.out.println("Person类的三个参数的有参构造");
}
}
7.问题:能否用一个实例化对象去调用它的构造方法?
不能。 构造方法就是去产生对象,如果用构造方法产生的对象去调用产生它的构造方法,就相当于自己又在自己的构造方法(我生我自己)
注:JVM产生对象时调用构造方法,对象实例化结束,无法在程序中手动调用构造方法再次实例化对象的!!!
(一)this关键字调用当前对象的成员变量
public class Test {
public static void main(String[] args) {
Person person = new Person("小韩",18,"女");
person.print();
}
}
class Person{
//成员变量
String name;
int age;
String sex;
public Person(String name,int age,String sex){//形参
name = name;
age = age;
sex = sex;
System.out.println("Person类的有参构造");
}
public void print(){
System.out.println("name:"+name+", age:"+age+", sex:"+sex);
}
}
问:为什么通过构造方法给成员变量初始化了,但输出结果仍是默认值?
形参名称与成员变量名称相同。程序设计理念:就近匹配原则,编译器会找最近的相同名称的变量在哪
问:如何打破就近匹配原则,从类中找同名变量呢?
使用this关键字
public Person(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("Person类的有参构造");
}
(二)this关键字调用当前对象的方法
(1)调用普通的成员方法
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.fun();
}
}
class Student{
String name;
int age;
String sex;
public void test(){
System.out.println("Student类的test成员方法");
}
public void fun(){
//test()方法是成员方法,必须通过对象调用
//this表示对象的引用,调用成员方法时不写,编译时也会自动加上
test();//==this.test();
System.out.println("Student类的fun成员方法");
}
}
(2)构造方法的相互调用
若不同参数的构造方法之间出现了重复的调用,可以使用 this(参数)调用其他的构造方法。
public Student(){
System.out.println("*******");
}
public Student(String name){
//调用无参构造
this();
this.name = name;
}
public Student(String name,int age){
//调用参数为name的一个参数的有参构造
this(name);
this.age = age;
}
注意要点:
1.this调用其他的构造方法必须放在当前构造方法的首行
2.this调用构造方法不能成环(否则构造方法就死循环了)
(三)this关键字表示当前对象的引用
(当前是通过哪个对象调用的属性或者方法,this就指代此对象)
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1);
student1.fun();
System.out.println();
Student student2 = new Student();
System.out.println(student2);
student2.fun();
}
}
class Student{
String name;
int age;
String sex;
public void fun(){
System.out.println(this);
}
}
代码块:指的是使用{ }括起来的一段代码,称为代码块。根据定义的代码块的位置以及关键字的不同分为以下四种代码块。
(一)普通代码块
定义在方法中,使用{ }括起来的一段代码。
public static void main(String[] args) {
//普通代码块
}
(二)成员代码块
定义在类中,不加任何修饰符的代码块,又称构造块。优先于构造方法执行,有几个对象产生就调用几次构造块。
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
}
}
class Student{
String name;
{
//构造块
System.out.println("Student类的构造块");
}
public Student(){
System.out.println("Student类的无参构造");
}
}
(三)静态代码块
定义在类中,使用static修饰的代码块,在类加载时执行一次,与对象无关。无论产生多少对象,静态代码块只在类加载时执行一次。
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
}
}
class Student{
String name;
{
//构造块
System.out.println("Student类的构造块");
}
public Student(){
System.out.println("Student类的无参构造");
}
static {
//静态代码块
System.out.println("Student类的静态代码块");
}
}
主类中的静态代码块优先于主方法执行。(JVM要执行主方法,首先要加载主类,主类一加载,静态块就执行了)
public class Test {
static {
System.out.println("主类的静态代码块");
}
public static void main(String[] args) {
System.out.println("进入主方法");
}
}
静态变量存在于方法区中,类定义时就会有初始值(在以下代码中,初始值为10),类此时在方法区中。但此时类只是定义了,还没被加载。当主方法中使用了该类时,就需要把该类从方法区加载到内存中。类加载后,静态代码块就被执行了(age= 10——>age = 100)
public class Test {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.age);
}
}
class Student{
static int age = 10;
static {
age = 100;
System.out.println("Student类的静态代码块");
}
public Student(){
System.out.println("Student类的无参构造");
}
}
(四)同步代码块(本篇博客暂不涉及)
八、其他
1.匿名对象:new出来的对象,没有引用指向,使用一次后就被JVM销毁。常用于测试类中的某些功能。
如 :new Person();
2、toString方法(注意大小写)
当一个引用类型的变量调用println函数打印时,默认输出的都是引用类型的地址。(不是真正的内存地址,Java中程序员是无法知道任何确认的内存地址)
public class Test {
public static void main(String[] args) {
System.out.println(new Student("小王"));
System.out.println(new Student("小李"));
}
}
class Student{
private String name;
static {
System.out.println("Student类的静态代码块");
}
public Student(){
System.out.println("Student类的无参构造");
}
public Student(String name){
this.name = name;
System.out.println("Person类的有参构造");
}
}
在类中构造一个toString()方法,对象默认调用此方法进行打印。
public String toString(){
String ret = "name:"+this.name;
return ret;
}