您的位置 首页 java

三石说:java基础 类与对象

类:

类是封装对象的行为和属性的载体,具有相同属行和行为的一类实体。类中包含方法和属性。

类中的构造方法:

1.构造方法没有返回值2.名称与类名相同,在构造方法中可以为成员变量赋值,也就是初始化成员变量,若在类中的构造方法都不是无惨的构造方法,编译器不会为类设置一个无参的构造方法,在类中没有设置构造方法时编译器才会在类中自定义一个无参的构造方法;

类中的成员方法:

成员方法对应于类对象的行为,成员方法可以是有参也可以是无参,可以有返回值也可以没有返回值,成员方法中可以调用其他成员方法也可以调用类成员变量,成员方法中也可以定义成员变量这是的成原变量为局部变量, 静态成员变量,静态成员方法:都用 类名.成员方法名。类名.成员变量掉用。静态方法中不可以用this关键字,静态方法不能直接调用非静态方法静态类中不能用this传值,可以用 return进行返回值,和直接输出;用来测试静态方法

1.静态方法不可以访问非 静态变量

2.非静态方法可以访问静态方法;

静态方法或属性在类加载时产生的。非静态方法是在new中产生的调用静态方法的格式:类名.静态方法名(参数);

This关键字:

this也可以调用成员方法和成员变量只是不太规范。主要用于当前对象的调用;This也可以做为方法的返回值

this可以在当前方法中获取当前对象的引用。

static 关键字:

new创建对象,数据存储空间才会分配,其方法才会对外界调用。而static修饰的:(1)如果没有创建对象,也可以进行调用这个方法。(2)只想为某特定的区域分配单一存储空间,而不考虑究竟创建出多少对象。

当一个事物声明static那就意味着这个域或方法不会与包含他那个类所关联在一起,所以即使从未创建某个类的任何对象,也可以调用其static方法,或访问static域。

比如:

class StaticTest{

static int i= 47;

String a =1;

}

StaticTest st1=new StaticTest();

StaticTest st22=new StaticTest();

st1.i和st22.i指向的是同一个存储空间,他们具有相同的值。

尽管当static作用于某个字段时,肯定会改变数据创建的方式(因为一个static字段对每个类来说都只有一份存储空间,而非static字段则是对每个对象有一存储空间)

static方法的内部能调用非静态方法。

static加载顺序:

父类静态代码块->子类静态代码块–>父类非静态代码块–>父类构造方法–>子类非静态代码块–>子类构造方法。

Super关键字:

子类可易继承父类的非私有变量,和方法作为自己的成员变量和成员方法,子类中的方法名与父类的方法名相同时称为子类隐藏了父类的成员变量,子类不能继承父类的成员方法,此时称为重写父类的成员变量;

若子类想访问父类中被子类隐藏的成员方法或变量时可以用super关键字 此时必须由子类来使用super关键字;用途:

1.super(参数列表);调用父类有参的 构造器

2.操作被隐藏在父类中的成员变量或被重写的方法格式:super.成员变量名 必须放在方法的第一个语句中;

Super.成员方法名([参数列表])Extends 子类继承父类,子接口继承父接口,implements子类对接口的实现

final关键字:

final作用于数据,方法,类。

1.一个永不改变的编译时常量。

2.一个在运行时被初始化的值,而你不希望它被改变。

一个既是static又是final的域只占据一段不能改变的存储空间。

空白的final: Java 允许生成一个空白的final;所谓的空白的final是指的被声明为final但又未给定初始值的域。比如: private final int j;

final参数 :java允许声明一个参数为final的对象。

void(final Gizmo g){

g=new Gizmo() // Illegal —g is final

}

final方法: 定义为final方法的原因有两个;1.把方法锁定,以防止任何继承类修改它的含义(保持不变,防止覆盖)。2.是效率

private和final关键字: 类中所有的private方法都隐式的指定为final,由于无法取用private方法,所以也就无法进行覆盖他,对于private方法添加final关键字并不能给方法增加任何意义。

final类: 将类设置为final即使永远不需要做任何变动,或者出于安全不希望有子类。由于final类禁止继承,所以final类的方法都隐式的指定为final的,因为无法覆盖他们,同样也可以给final类的方法添加final修饰词,但是这没有任何意义。

final修饰引用类型的时候,引用的指向不能修改,但是引用的值可以改

final Student stu = new Student(1,”assd”);

stu.setAge(12); // 这里是可以的,因为改变的是堆内存中的数据,引用还是指的这一个堆内存地址。

stu=new Student(); // 这里是不允许的因为,final类型是不可以变的。

final好处:

1.final关键字提高了性能。 JVM 和Java应用都会缓存final变量。

2.final变量可以安全的在多线程的环境下共享,而不需要额外的同步开销。

3.使用final关键字,JVM会对方法,变量进行优化。

final修饰的String类

String 类代表 字符串 。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。

 public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /**该值用于字符存储。  */    private final char value[];

    /**  缓存字符串的哈希代码*/    private int hash; // Default to 0

    /** 使用jdk1.0.2中的serialVersionUID实现互操作性*/    private static final long serialVersionUID = -6849794470754667710L;

    /**
     * 类字符串在序列化流协议中是特殊大小写的。
     */    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
    /**
     *初始化新创建的{@code String}对象,使其表示空字符序列。请注意,此构造函数的用法是没有必要,因为字符串是不可变的。
     */    public String() {
        this.value = "".value;
    }  
 直接赋值方式创建对象是在方法区的常量池
String str="hello";//直接赋值的方式

通过构造方法创建字符串对象是在堆内存
String str=new String("hello");//实例化的方式

1)直接赋值(String str = "hello"):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。

2)构造方法(String str=  new String("hello");):会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收,而且不能够自动入池,需要通过public  String intern();方法进行手工入池。

在开发的过程中不会采用构造方法进行字符串的实例化。  

Q&A String的不可变性

 Strings are constant; their values cannot be changed after theyare created. String buffers support mutable strings.Because String objects are immutable they can be shared. 
    For example:
 String str = "abc";
 与下面的相等;
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * Here are some more examples of how strings can be used:
 * <blockquote><pre>
 *     System.out.println("abc");
 *     String cde = "cde";
 *     System.out.println("abc" + cde);
 *     String c = "abc".substring(2,3);
 *     String d = cde.substring(1, 2);
 * </pre></blockquote>
 * <p>  

Q&A 为何String设计为不可变?

1、运行时常量池的需要,节省内存空间。

  比如执行 String s = “abc”;执行上述代码时,JVM首先在运行时常量池中查看是否存在String对象“abc”,如果已存在该对象,则不用创建新的String对象“abc”,而是将引用s直接指向运行时常量池中已存在的String对象“abc”;如果不存在该对象,则先在运行时常量池中创建一个新的String对象“abc”,然后将引用s指向运行时常量池中创建的新String对象。这样在运行时常量池中只会创建一个String对象”abc”,这样就节省了内存空间。

2、同步

  因为String对象是不可变的,所以是多线程安全的,同一个String实例可以被多个线程共享。这样就不用因为线程安全问题而使用同步。

3、允许String对象缓存 hashcode

  查看上文JDK1.8中String类源码,可以发现其中有一个字段hash,String类的不可变性保证了hashcode的唯一性,所以可以用hash字段对String对象的hashcode进行缓存,就不需要每次重新计算hashcode。所以Java中String对象经常被用来作为HashMap等容器的键。

4、安全性

  如果String对象是可变的,那么会引起很严重的安全问题。比如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为String对象是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变String引用指向的对象的值,造成安全漏洞。

Q&A String s = new String(“xyz”);创建了几个String Object?二者之间有什么区别?

两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新String对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。

对象:

对象是通过new关键字来创建的,通过引用来接收对象,当对象创建出来后引用就会为对象分配内存,new字是创建对象的操作符,对象的比较有两种形式:

1.“==”运算符是用来比较两个对象引用的地址是否相等,

2.“equal()”方法是来比较两对象引用的内容是否相等。对象的销毁是引用结束后就会被垃圾处理器进行回收;

Q&A 创建对象的方法:

1.使用new关键字。

2.使用Class类中的newInstance方法,newInstance方法调用无参构造方器创建对象。Class.forName.newInstance;

3.使用clone方法、

4.反序列化。

Q&A 对象的产生过程以及存储:

对象的产生:

new将对象存储在堆中,所以用new创建一个对象—特别小的,简单的变量,往往不是很有效。因此对于(基本类型)java不用new来创建这样的变量,而是创建一个并非是引用的“自动”变量。这个变量的值直接存储”值”到堆栈中。

程序创建,运行时对象是如何分配呢?内存是怎样分配呢?

对象产生的时机 类加载,然后进行对象的实例化:

#####Q&A 什么时候会进行类加载?

1.创建类的实例,也就是new一个对象

2.访问某个类或接口的静态变量,或者对该静态变量赋值

3.调用类的静态方法

4.反射(Class.forName(“A”))

5.初始化一个类的子类(会首先初始化子类的父类)

6.JVM启动时标明的启动类,即文件名和类名相同的那个类

new ObjectInitTest() 对象的产生过程 1.JVM会在ObjectInitTest.class文件 2.先加载类级别的成员(静态成员变量 静态块初始化) 3.再加载对象级别的成员(实例成员变量 实例块初始化)

Q&A什么时候进行对象的实例化?

类加载成功(或已加载过)后,就开始进行对象的实例化了。对象的实例化依次进行了如下几个步骤:

1.对象在堆中的内存空间分配

2.初始化零值,这时会将实例变量都赋予零值

3.设置对象头,对象头保存了一些对象在运行期的状态信息,包括类信息地址(知道对象是属于哪个类的)、hashcode(用于hashmap和hashset等hash结构中)、GC分代年龄(可以依此确定对象何时该放入老年代)等

4.init方法执行,这时对变量的实例变量进行初始化

对象初始化的过程也是线程安全的动作。

StringBuffer StringBulider String 的区别:

StringBuffer线程安全,StringBulider线程不安全,底层实现StringBuffer比StringBulider多一个Synchronized.从源码中可以看得到:

 StringBuffer源码分析:
@Override
    public synchronized int length() {
        return count;
    }

    @Override
    public synchronized int capacity() {
        return value.length;
    }


    @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > value.length) {
            expandCapacity(minimumCapacity);
        }
    }

    /**
     * @since      1.5
     */    @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */    @Override
    public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */    @Override
    public synchronized char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }  

String 是否可以继承,“+”如何实现的,与StringBuffer区别?

java中通过使用“+”符号串联时实际是使用的StringBuilder实例的appdenf()方法来实现的。

构造器

考虑到在初始化期间要自动代用构造器,构造器采用与类名相同的名称,在java中“初始化”和“创建”捆绑在一起,两者不能分离。

  • 是一个类创建对象的根本途径,如果一个类没有构造器,这个类通常无法创建实例。因此, Java语言提供了一个功能:如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器静态变量调用:
  • Java编程时不要使用对象去调用static修饰的Field、方法,而是应该使用类去调用static修饰的Field、方法!如果在其他Java代码中看到对象调用static修饰的Field、方法的情形,完全可以把这种用法当成假象,将其替换成用类来调用static修饰的Field、方法的代码

文章来源:智云一二三科技

文章标题:三石说:java基础 类与对象

文章地址:https://www.zhihuclub.com/183336.shtml

关于作者: 智云科技

热门文章

网站地图