풀이1

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int col = sc.nextInt();
        int row = sc.nextInt();

        for(int i = 0 ; i < row ; i++) 
        {
            for(int j = 0 ; j < col ; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        sc.close();
    }
}

풀이2

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int col = sc.nextInt();
        int row = sc.nextInt();

        StringBuilder sb = new StringBuilder();
        String asta = "*";

        for(int i = 0 ; i < row ; i++) 
        {
            for(int j = 0 ; j < col ; j++) {
                sb.append(asta);
            }
            sb.append("\n");
        }

        System.out.println(sb.toString());
        sc.close();
    }
}

String 객체는 내부적으로 char 배열을 사용하기 때문에 변하지 X
문자열 연산이 많아질수록 계속해서 객체를 생성하게되어 오버헤드가 발생, 성능이 떨어질 수 있다.
단, 객체가 불변하기 때문에 단순 읽기 작업시 타 클래스보다 빠르다.

StringBuilder, StringBuffer 클래스는 변경 O
한번 객체를 생성하여 크기를 변경시켜 값(문자열)을 변경하므로 문자열 연산이 빈번할 경우 사용하기 좋다.
StringBuffer 동기화 가능, 멀티스레드 환경에서 사용.
StringBuilder 비동기화, 싱글스레드 혹은 스레드를 고려하지 않아도 될 때 사용.