    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one
    003 * or more contributor license agreements.  See the NOTICE file
    004 * distributed with this work for additional information
    005 * regarding copyright ownership.  The ASF licenses this file
    006 * to you under the Apache License, Version 2.0 (the
    007 * "License"); you may not use this file except in compliance
    008 * with the License.  You may obtain a copy of the License at
    009 *
    010 *   https://www.apache.org/licenses/LICENSE-2.0
    011 *
    012 * Unless required by applicable law or agreed to in writing,
    013 * software distributed under the License is distributed on an
    014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015 * KIND, either express or implied.  See the License for the
    016 * specific language governing permissions and limitations
    017 * under the License.
    018 */
    019package org.apache.bcel.generic;
    020
    021import org.apache.bcel.Const;
    022
    023/**
    024 * Denotes array type, such as int[][]
    025 */
    026public final class ArrayType extends ReferenceType {
    027
    028    private final int dimensions;
    029    private final Type basicType;
    030
    031    /**
    032     * Convenience constructor for array type, for example int[]
    033     *
    034     * @param type array type, for example T_INT.
    035     * @param dimensions array dimensions.
    036     */
    037    public ArrayType(final byte type, final int dimensions) {
    038        this(BasicType.getType(type), dimensions);
    039    }
    040
    041    /**
    042     * Convenience constructor for reference array type, for example Object[]
    043     *
    044     * @param className complete name of class ({@link String}, for example).
    045     * @param dimensions array dimensions.
    046     */
    047    public ArrayType(final String className, final int dimensions) {
    048        this(ObjectType.getInstance(className), dimensions);
    049    }
    050
    051    /**
    052     * Constructor for array of given type
    053     *
    054     * @param type type of array (may be an array itself).
    055     * @param dimensions array dimensions.
    056     */
    057    public ArrayType(final Type type, final int dimensions) {
    058        super(Const.T_ARRAY, "<dummy>");
    059        if (dimensions < 1 || dimensions > Const.MAX_BYTE) {
    060            throw new ClassGenException("Invalid number of dimensions: " + dimensions);
    061        }
    062        switch (type.getType()) {
    063        case Const.T_ARRAY:
    064            final ArrayType array = (ArrayType) type;
    065            this.dimensions = dimensions + array.dimensions;
    066            basicType = array.basicType;
    067            break;
    068        case Const.T_VOID:
    069            throw new ClassGenException("Invalid type: void[]");
    070        default: // Basic type or reference
    071            this.dimensions = dimensions;
    072            basicType = type;
    073            break;
    074        }
    075        final StringBuilder buf = new StringBuilder();
    076        for (int i = 0; i < this.dimensions; i++) {
    077            buf.append('[');
    078        }
    079        buf.append(basicType.getSignature());
    080        this.signature = buf.toString();
    081    }
    082
    083    /**
    084     * @return true if both type objects refer to the same array type.
    085     */
    086    @Override
    087    public boolean equals(final Object type) {
    088        if (type instanceof ArrayType) {
    089            final ArrayType array = (ArrayType) type;
    090            return array.dimensions == dimensions && array.basicType.equals(basicType);
    091        }
    092        return false;
    093    }
    094
    095    /**
    096     * Gets the basic type of array, that is, for int[][][] the basic type is int.
    097     *
    098     * @return basic type of array, that is, for int[][][] the basic type is int.
    099     */
    100    public Type getBasicType() {
    101        return basicType;
    102    }
    103
    104    /**
    105     * Gets the name of referenced class.
    106     *
    107     * @return name of referenced class.
    108     * @since 6.7.0
    109     */
    110    @Override
    111    public String getClassName() {
    112        return signature;
    113    }
    114
    115    /**
    116     * Gets the number of dimensions of array.
    117     *
    118     * @return number of dimensions of array.
    119     */
    120    public int getDimensions() {
    121        return dimensions;
    122    }
    123
    124    /**
    125     * Gets the element type of array, that is, for int[][][] the element type is int[][].
    126     *
    127     * @return element type of array, that is, for int[][][] the element type is int[][].
    128     */
    129    public Type getElementType() {
    130        if (dimensions == 1) {
    131            return basicType;
    132        }
    133        return new ArrayType(basicType, dimensions - 1);
    134    }
    135
    136    /**
    137     * @return a hash code value for the object.
    138     */
    139    @Override
    140    public int hashCode() {
    141        return basicType.hashCode() ^ dimensions;
    142    }
    143}