一.类与对象的基本概念
类与对象是整个面向对象中最基础的组成单元。
类: 是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象: 对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
可以用一句话来总结出类和对象的区别:类是对象的模板,对象是类的实例。类只有通过对象才可以使用,而在开发之中应该先产生类,之后再产生对象。类不能直接使用,对象是可以直接使用的。
二.类与对象的关系
什么是对象
面向对象程序设计(OOP)就是使用对象进行程序设计。对象(Object)代表现实世界中可以明确
标识的一个实体。
一个对象的状态(state,也称为特征(property)或者属性(arrtibute))是由具有当前值的
数据域来表示的。我们一般把对象的特有属性称之为成员变量。
一个对象的行为(behavior,也称为动作(action))是由方法定义的。调用对象的一个方法
就是要求对象完成一个动作。我们一般把对象的行为称之为成员函数。
什么是类
使用一个通用类来定义同一类型的对象。类是一个模板、蓝本或者说是合约,用来定义对象的数据
域是什么以及方法是做什么的。一个对象是类的一个实例。可以从一个类中创建多个实例。创建实例的
过程称为实例化。对象和实例经常是可以互换的。类和对象之间的关系类似于苹果派配方和苹果派之间
的关系。可以用一种配方做出任意多的苹果派来。
Java类使用变量定义数据域,使用方法定义动作。除此之外,类还提供了一种称为构造方法
(constructor)的特殊类型的方法,调用它可以创建一个新对象。构造方法本身是可以完成任何
动作的,但是设计构造方法是为了完成初始化动作。
三、类与对象的定义和使用
在Java中定义类,使用关键字class完成。语法如下:
class 类名称 {
属性 (变量) ;
行为 (方法) ;
}
例: 定义一个Person类
class Person { // 类名称首字母大写
String name ;
int age ;
public void tell() { // 没有static
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
类定义完成之后,肯定无法直接使用。如果要使用,必须依靠对象,那么由于类属于引用数据类型,所以对象的产生格式(两种格式)如下:
(1)格式一:声明并实例化对象
类名称 对象名称 = new 类名称 () ;
(2)格式二:先声明对象,然后实例化对象:
类名称 对象名称 = null ;
对象名称 = new 类名称 () ;
引用数据类型与基本数据类型最大的不同在于:引用数据类型需要内存的分配和使用。所以,关键字new的主要功能就是分配内存空间,也就是说,只要使用引用数据类型,就要使用关键字new来分配内存空间。
当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
对象.属性: 表示调用类之中的属性;
对象.方法(): 表示调用类之中的方法。
例: 使用对象操作类
package com.openlab.classandobj;
class Person {
String name ;
int age ;
public void get() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class TestDemo {
public static void main(String args[]) {
Person per = new Person() ;// 声明并实例化对象
per.name = "张三" ;//操作属性内容
per.age = 30 ;//操作属性内容
per.get() ;//调用类中的get()方法
}
}
运行结果:姓名:张三,年龄:30
四、private关键字,this关键字以及static关键字
1.private关键字的作用
在一个类中,一旦使用private进行修饰,那么本类中仍然可以随意访问;
但是超出本类范围就不能直接访问了。
间接访问private成员变量,就是定义一个Getter和Setter方法。
一般对成员属性的访问动作:修改器(设置 set),访问器(获取 get),因此对私有的变量访问的
方式可以提供对应的 setXxx或者getXxx的方法。
命名规则: 必须叫setXxx或者是getXxx,
对于Getter来说,不能有参数,返回值类型和成员变量对应。
对于Setter来说,不能有返回值,参数类型和成员变量对应。
代码示例:
public class Person {
private String name; //姓名
private int age; //年龄
public void show(){
System.out.println("我叫"+name+"年龄"+age);
}
//成员方法专门用于向age设置数据
public void setAge(int num){
if(num<100&&num>=0){
age = num;
} else {
System.out.println("数据不合理!");
}
}
//成员方法专门用于向name设置数据
public void setName(String na){
name = na;
}
//成员方法专门用于获取age的数值
public int getAge(){
return age;
}
//成员方法专门用于获取name的数值
public String getName(){
return name;
}
}
2.this关键字的作用
this关键字主要有三个应用:
(1)this调用本类中的属性,也就是类中的成员变量;
(2)this调用本类中的其他方法;
(3)this调用本类中的其他构造方法,调用时要放在构造方法的首行。
应用一:引用成员变量
Public Class Student {
String name; //定义一个成员变量name
private void SetName(String name) { //定义一个参数(局部变量)name
this.name=name; //将局部变量的值传递给成员变量
}
}
应用二:调用类的构造方法
public class Student { //定义一个类,类的名字为student。
public Student() { //定义一个方法,名字与类相同故为构造方法
this(“Hello!”);
}
public Student(String name) { //定义一个带形式参数的构造方法
}
}
应用三:返回对象的值
this关键字除了可以引用变量或者成员方法之外,还有一个重大的作用就是返回类的引用。
如在代码中,可以使用return this,来返回某个类的引用。此时这个this关键字就代表类的名称。
如代码在上面student类中,那么代码代表的含义就是return student。
可见,这个this关键字除了可以引用变量或者成员方法之外,还可以作为类的返回值,这才是this关键字最引人注意的地方。
3.static关键字的作用
1)修饰成员变量
在我们平时的使用当中,static最常用的功能就是修饰类的属性和方法,让他们成为类的成员属性和方法,我们通常将用static修饰的成员称为类成员或者静态成员,这句话挺起来有点奇怪,其实这是相对于对象的属性和方法来说的。
请看下面的例子:
public class Person {
String name;
int age;
public String toString() {
return "Name:" + name + ", Age:" + age;
}
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "zhangsan";
p1.age = 10;
Person p2 = new Person();
p2.name = "lisi";
p2.age = 12;
System.out.println(p1);
System.out.println(p2);
}
}
2.修饰成员方法
static的另一个作用,就是修饰成员方法。相比于修饰成员属性,修饰成员方法对于数据的存储上面并没有多大的变化,因为我们从上面可以看出,方法本来就是存放在类的定义当中的。static修饰成员方法最大的作用,就是可以使用"类名.方法名"的方式操作方法,避免了先要new出对象的繁琐和资源消耗,我们可能会经常在帮助类中看到它的使用:
public class Test {
public static void print(Object o){
System.out.println(o);
}
public static void main(String[] args) {
Test .print("Hello world");
}
}
3.静态块
当我们初始化static修饰的成员时,可以将他们统一放在一个以static开始,用花括号包裹起来的块状语句中:
class Book{
public Book(String msg) {
System.out.println(msg);
}
}
public class Person {
Book book1 = new Book("book1成员变量初始化");
static Book book2;
static {
book2 = new Book("static成员book2成员变量初始化");
book4 = new Book("static成员book4成员变量初始化");
}
public Person(String msg) {
System.out.println(msg);
}
Book book3 = new Book("book3成员变量初始化");
static Book book4;
public static void funStatic() {
System.out.println("static修饰的funStatic方法");
}
public static void main(String[] args) {
Person.funStatic();
System.out.println("****************");
Person p1 = new Person("p1初始化");
}
/**Output
* static成员book2成员变量初始化
* static成员book4成员变量初始化
* static修饰的funStatic方法
* ***************
* book1成员变量初始化
* book3成员变量初始化
* p1初始化
*///~
}
4.静态导包
导包时添加static关键字,使被导入类中的静态方法/静态变量在当前类可直接调用,而无需使用类名加点的方式
导入语法:
import static 包名.类名.静态成员变量;
import static 包名.类名.静态成员方法;
import static 包名.类名.*;
未使用静态导入
public static void main(String[] args) {
//调用math类中的random()方法生成随机数
System.out.println(Math.random());
}
未使用静态导入时,需要通过类名Math加具体方法名random()来进行调用生成随机数
使用静态导入
import static java.lang.Math.random;
public class Demo {
public static void main(String[] args) {
//无需类名,直接通过random()方法生成随机数
System.out.println(random());
}
}
注意:
静态导入可减少代码输入量,但当两个不同的类中有命名相同的方法都使用静态导入时,仍然需要通过 类名 Math加 具体方法名 random()来进行调用,否则会报错!
总结:
static是java中非常重要的一个关键字,而且它的用法也很丰富,主要有四种用法:
- 用来修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享;
- 用来修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类;
- 静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键;
- 静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便。
五、构造函数
构造函数的最大作用就是创建对象时完成初始化,当我们在new一个对象并传入参数的时候,会自动调用构造函数并完成参数的初始化
构造函数的规则:
构造函数与类同名
每个类可以有一个以上的构造函数
构造函数可以有0 个 、 1 个或多个参数
构造函数没有返回值
构造函数总是伴随着new操作一起调用
看一个例子:
public class Employee {
// 关键字 private 确保只有 Employee 类自身的方法能够访问这些实例域 , 而其他类的方法不能够读写这些域 。
// 可以用 public 标记实例域 , 但这是一种极为不提倡的做法
//public 數据域允许程序中的任何方法对其进行读取和修改 ,。 这就完全破坏了封装 。
//任何类的任何方法都可以修改 public 域 , 从我们的经验来看 , 某些代码将使用这种存取权限 , 而这并不我们所希
//望的 , 因此这里强烈建议将实例域标记为 private , ,
private String name ;
private double salary ;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
public static void main(String[] args) {
// 说明在我们创建Employee对象的时候,会自动调用构造函数完成初始化,
Employee employee = new Employee("John",44545);
System.out.println(employee);
}
}
细节:
- 如果你不写构造函数,程序会自动给你加上一个无参数无操作的构造函数(当然你看不见)
- 如果你写了构造函数,则自定义构造函数会覆盖无参数构造函数
public class Employee_1 {
@Override
public String toString() {
return "Employee_1{}";
}
public static void main(String[] args) {
// 没有显式提供构造函数
// 程序会自动给你加上一个无参数无操作的构造函数
Employee_1 employee_1 = new Employee_1();
System.out.println(employee_1);
}
}
构造函数与普通函数的区别:
- 一般函数是用于定义对象应该具备的功能。而构造函数定义的是,对象在调用功能之前,在建立时,应该具备的一些内容。也就是对象的初始化内容。
- 构造函数是在对象建立时由JVM调用, 给对象初始化。一般函数是对象建立后,当对象调用该功能时才会执行。
- 普通函数可以使用对象多次调用,构造函数就在创建对象时调用。
- 构造函数的函数名要与类名一样,而普通的函数只要符合标识符的命名规则即可。
- 构造函数没有返回值类型。
初始化
为什么需要初始化?
java规定,变量没有初始化不能使用,全局变量也就是类的属性,java会在编译的时候,自动将他们初始化,所以可以不进行变量初始化的操作,但是(局部)变量必须初始化。
初始化就是在最开始定义成员变量时给它一个初始的值,为了防止程序运行时候出现未知的错误,或者bug,总之一句话,为了安全。
默认初始化
在Java中,一个类的数据成员(成员变量)如果没有指定初始化,那么Java会对其执行默认初始化
public class InitialValues {
boolean t;
char c;
short s;
int i;
long l;
float f;
double d;
String str;
InitialValues reference;
void printInitialValues() {
System.out.printf("%-10s %-5s\n", "boolean:", t);
System.out.printf("%-10s %-5s\n", "char:", c);
System.out.printf("%-10s %-5s\n", "short:", s);
System.out.printf("%-10s %-5s\n", "int:", i);
System.out.printf("%-10s %-5s\n", "long:", l);
System.out.printf("%-10s %-5s\n", "float:", f);
System.out.printf("%-10s %-5s\n", "double:", d);
System.out.printf("%-10s %-5s\n", "String:", str);
System.out.printf("%-10s %-5s\n", "reference:", reference);
}
public static void main(String[] args) {
InitialValues iv = new InitialValues();
iv.printInitialValues();
}
}
/*
输出内容
boolean: false
char:
short: 0
int: 0
long: 0
float: 0.0
double: 0.0
String: null
reference: null
*/
静态数据的初始化
初始化的顺序是:先静态对象,而后是“非静态”对象。
class Bowl{
Bowl(int marker){
System.out.println("Bowl("+marker+")");
}
void f1(int marker){
System.out.println("f1("+marker+")");
}
}
class Table{
static Bowl bowl1=new Bowl(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2("+marker+")");
}
static Bowl bowl2= new Bowl(2);
}
class Cupboard{
Bowl bowl3=new Bowl(3);
static Bowl bowl4=new Bowl(4);
Cupboard(){
System.out.println("Cupboard()");
bowl4.f1(2);
}
void f3(int marker){
System.out.println("f3("+marker+")");
}
static Bowl bowl5= new Bowl(5);
}
public class StaticInitialization {
// 要执行main(),必须加载StaticInitialization类,然后其静态域table和cupboard被初始化,这导致他们对应的类也被加载,并且由于它们都包含静态的Bowl对象,
// 因此Bowl随后也被加载。这样,在这个特殊的程序中的所有的类在main()开始之前就都被加载了。
//
// 首先从main()函数开始,加载StaticInitializaition类,然后对StaticInitializaition类中的静态域Table进行初始化,加载Table类,Table类中包含静态的Bowl对象,
// 接着加载Bowl类,加载Bowl类构造器创建bowl1对象,输出Bowl(1),加载Bowl类构造器创建bowl2对象,输出Bowl(2);同里创建cupboard对象。
//
// 需要注意的是,bowl3是非静态域,每次创建Cupboard对象都会创建一个Bowl对象。
public static void main(String[] args) {
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
非静态成员初始化
在一个类中,非静态成员的初始化,发生在任何方法(包括构造器)被调用之前。并且它们定义的顺序,决定了初始化的顺序。
class A{
A(String s) {
System.out.println(s);
}
}
class B{
A a1 = new A("a1");
B() {
System.out.println("B");
A a2 = new A("a2");
}
A a3 = new A("a3");
void f(){
System.out.println("f---");
}
A a4 = new A("a4");
}
public class Initialization_1 {
public static void main(String[] args) {
B b = new B();
b.f();
}
}
静态块代码初始化
整个static { 静态代码块 } 可以看作是一个静态成员。当一个类需要执行静态初始化时,该类中的静态成员初始化和静态代码块,会按照先后定义的顺序执行。当然,这个流程也是就执行这一次。
class AA{
public AA(String s) {
System.out.println(s);
}
}
class BB{
AA a1 = new AA("a1");
static AA a2 = new AA("a2");
static AA a3,a4;
static {
System.out.println("______________");
a3 = new AA("a3");
a4 = new AA("a4");
AA a5 = new AA("a5");
System.out.println("++++++++++++");
}
static AA a6 = new AA("a6");
AA a7 = new AA("a7");
public BB() {
System.out.println("BB");
}
}
public class Initialization_3 {
static BB b1 = new BB();
public static void main(String[] args) {
new BB();
}
}
非静态代码初始化
非静态代码块,可以看作一个非静态成员。涉及非静态初始化,也会执行它。和普通的非静态成员初始化一样,它的执行也发生在构造器调用之前,并且每当创建对象之前都会调用。
class AA{
public AA(String s) {
System.out.println(s);
}
}
class BB{
AA a1 = new AA("a1");
static AA a2 = new AA("a2");
static AA a3,a4;
{
System.out.println("______________");
a3 = new AA("a3");
a4 = new AA("a4");
AA a5 = new AA("a5");
System.out.println("++++++++++++");
}
static AA a6 = new AA("a6");
AA a7 = new AA("a7");
public BB() {
System.out.println("BB");
}
}
public class Initialization_4 {
static BB b1 = new BB();
public static void main(String[] args) {
new BB();
}
}